Commit 5b30b06d authored by Davis King's avatar Davis King
Browse files

merged

parents e4ae6686 2e1927cd
...@@ -384,6 +384,11 @@ namespace dlib ...@@ -384,6 +384,11 @@ namespace dlib
{ {
static const bool value = true; static const bool value = true;
}; };
template <typename T>
struct is_const_type<const T&>
{
static const bool value = true;
};
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
......
...@@ -487,6 +487,14 @@ namespace dlib ...@@ -487,6 +487,14 @@ namespace dlib
} }
} }
// ----------------------------------------------------------------------------------------
template <typename T, typename MM>
struct is_array2d <array2d<T,MM> >
{
const static bool value = true;
};
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
} }
......
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_DISJOINt_SUBSETS_
#define DLIB_DISJOINt_SUBSETS_
#include "disjoint_subsets/disjoint_subsets.h"
#endif // DLIB_DISJOINt_SUBSETS_
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_DISJOINT_SUBsETS_H__
#define DLIB_DISJOINT_SUBsETS_H__
#include "disjoint_subsets_abstract.h"
#include <vector>
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class disjoint_subsets
{
public:
void clear (
)
{
items.clear();
}
void set_size (
unsigned long new_size
)
{
items.resize(new_size);
for (unsigned long i = 0; i < items.size(); ++i)
{
items[i].parent = i;
items[i].rank = 0;
}
}
unsigned long size (
) const
{
return items.size();
}
unsigned long find_set (
unsigned long item
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(item < size(),
"\t unsigned long disjoint_subsets::find_set()"
<< "\n\t item must be less than size()"
<< "\n\t item: " << item
<< "\n\t size(): " << size()
<< "\n\t this: " << this
);
if (items[item].parent == item)
{
return item;
}
else
{
// find root of item
unsigned long x = item;
do
{
x = items[x].parent;
} while (items[x].parent != x);
// do path compression
const unsigned long root = x;
x = item;
while (items[x].parent != x)
{
const unsigned long prev = x;
x = items[x].parent;
items[prev].parent = root;
}
return root;
}
}
unsigned long merge_sets (
unsigned long a,
unsigned long b
)
{
// make sure requires clause is not broken
DLIB_ASSERT(a != b &&
a < size() &&
b < size() &&
find_set(a) == a &&
find_set(b) == b,
"\t unsigned long disjoint_subsets::merge_sets(a,b)"
<< "\n\t invalid arguments were given to this function"
<< "\n\t a: " << a
<< "\n\t b: " << b
<< "\n\t size(): " << size()
<< "\n\t find_set(a): " << find_set(a)
<< "\n\t find_set(b): " << find_set(b)
<< "\n\t this: " << this
);
if (items[a].rank > items[b].rank)
{
items[b].parent = a;
return a;
}
else
{
items[a].parent = b;
if (items[a].rank == items[b].rank)
{
items[b].rank = items[b].rank + 1;
}
return b;
}
}
private:
/*
See the book Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein
for a discussion of how this algorithm works.
*/
struct data
{
unsigned long rank;
unsigned long parent;
};
mutable std::vector<data> items;
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_DISJOINT_SUBsETS_H__
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_DISJOINT_SUBsETS_ABSTRACT_H__
#ifdef DLIB_DISJOINT_SUBsETS_ABSTRACT_H__
#include <vector>
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class disjoint_subsets
{
/*!
INITIAL VALUE
- size() == 0
WHAT THIS OBJECT REPRESENTS
This object represents a set of integers which is partitioned into
a number of disjoint subsets. It supports the two fundamental operations
of finding which subset a particular integer belongs to as well as
merging subsets.
!*/
public:
void clear (
);
/*!
ensures
- #size() == 0
- returns this object to its initial value
!*/
void set_size (
unsigned long new_size
);
/*!
ensures
- #size() == new_size
- for all valid i:
- #find_set(i) == i
(i.e. this object contains new_size subsets, each containing exactly one element)
!*/
unsigned long size (
) const;
/*!
ensures
- returns the total number of integer elements represented
by this object.
!*/
unsigned long find_set (
unsigned long item
) const;
/*!
requires
- item < size()
ensures
- Each disjoint subset can be represented by any of its elements (since
the sets are all disjoint). In particular, for each subset we define
a special "representative element" which is used to represent it.
Therefore, this function returns the representative element for the
set which contains item.
- find_set(find_set(item)) == find_set(item)
- Note that if A and B are both elements of the same subset then we always
have find_set(A) == find_set(B).
!*/
unsigned long merge_sets (
unsigned long a,
unsigned long b
)
/*!
requires
- a != b
- a < size()
- b < size()
- find_set(a) == a
(i.e. a is the representative element of some set)
- find_set(b) == b
(i.e. b is the representative element of some set)
ensures
- #find_set(a) == #find_set(b)
(i.e. merges the set's containing a and b)
- returns #find_set(a)
!*/
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_H__
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "geometry/rectangle.h" #include "geometry/rectangle.h"
#include "geometry/vector.h" #include "geometry/vector.h"
#include "geometry/border_enumerator.h"
#endif // DLIB_GEOMETRy_HEADER #endif // DLIB_GEOMETRy_HEADER
......
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BORDER_EnUMERATOR_H_
#define DLIB_BORDER_EnUMERATOR_H_
#include "border_enumerator_abstract.h"
#include "rectangle.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class border_enumerator
{
public:
border_enumerator(
)
{
}
border_enumerator(
const rectangle& rect_,
unsigned long border_size
) :
rect(rect_),
inner_rect(shrink_rect(rect_, border_size))
{
reset();
}
void reset (
)
{
p = rect.tl_corner();
p.x() -= 1;
}
bool at_start (
) const
{
point temp = rect.tl_corner();
temp.x() -=1;
return temp == p;
}
bool current_element_valid(
) const
{
return rect.contains(p) && !inner_rect.contains(p);
}
bool move_next()
{
p.x() += 1;
if (p.x() > rect.right())
{
p.y() += 1;
p.x() = rect.left();
}
else if (inner_rect.contains(p))
{
p.x() = inner_rect.right()+1;
}
return current_element_valid();
}
unsigned long size (
) const
{
return rect.area() - inner_rect.area();
}
const point& element (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(current_element_valid(),
"\t point border_enumerator::element()"
<< "\n\t This function can't be called unless the element is valid."
<< "\n\t this: " << this
);
return p;
}
private:
point p;
rectangle rect;
rectangle inner_rect; // the non-border regions of rect
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BORDER_EnUMERATOR_H_
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_
#ifdef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_
#include "rectangle_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class border_enumerator
{
/*!
POINTERS AND REFERENCES TO INTERNAL DATA
All operations on this object other than calling element() invalidate
pointers and references to internal data.
WHAT THIS OBJECT REPRESENTS
This object is an enumerator over the border points of a rectangle.
!*/
public:
border_enumerator(
);
/*!
ensures
- #move_next() == false
(i.e. this object is "empty" and won't enumerate anything)
- current_element_valid() == false
- at_start() == true
- size() == 0
!*/
border_enumerator(
const rectangle& rect,
unsigned long border_size
);
/*!
ensures
- This object will enumerate over the border points which are inside rect
but within border_size of the edge. For example, if border_size == 1
then it enumerates over the single point wide strip of points all around
the interior edge of rect.
- current_element_valid() == false
- at_start() == true
- size() == rect.area() - shrink_rect(rect,border_size).area()
(i.e. the number of points in the border area of rect)
!*/
bool at_start (
) const;
/*!
ensures
- returns true if *this represents one position before the first point
(this would also make the current element invalid) else returns false
!*/
void reset (
);
/*!
ensures
- #current_element_valid() == false
- #at_start() == true
!*/
bool current_element_valid(
) const;
/*!
ensures
- returns true if we are currently at a valid element else
returns false
!*/
bool move_next(
);
/*!
ensures
- moves to the next element. i.e. #element() will now
return the next border point.
- the return value will be equal to #current_element_valid()
- #at_start() == false
- returns true if there is another element
- returns false if there are no more elements in the container
!*/
unsigned long size (
) const;
/*!
ensures
- returns the number of border points
!*/
const point& element (
) const;
/*!
requires
- current_element_valid() == true
ensures
- returns the current border point
!*/
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BORDER_EnUMERATOR_ABSTRACT_H_
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "image_transforms/integral_image.h" #include "image_transforms/integral_image.h"
#include "image_transforms/image_pyramid.h" #include "image_transforms/image_pyramid.h"
#include "image_transforms/label_connected_blobs.h" #include "image_transforms/label_connected_blobs.h"
#include "image_transforms/randomly_color_image.h"
#include "image_transforms/segment_image.h"
#endif // DLIB_IMAGE_TRANSFORMs_ #endif // DLIB_IMAGE_TRANSFORMs_
...@@ -27,6 +27,9 @@ namespace dlib ...@@ -27,6 +27,9 @@ namespace dlib
{ {
COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::is_unsigned == true ); COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::is_unsigned == true );
typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type in_image_basic_pixel_type;
COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) < sizeof(long));
// make sure hist is the right size // make sure hist is the right size
if (R == 1) if (R == 1)
hist.set_size(1,pixel_traits<typename in_image_type::type>::max()+1); hist.set_size(1,pixel_traits<typename in_image_type::type>::max()+1);
...@@ -64,6 +67,9 @@ namespace dlib ...@@ -64,6 +67,9 @@ namespace dlib
COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::is_unsigned == true ); COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::is_unsigned == true );
COMPILE_TIME_ASSERT( pixel_traits<typename out_image_type::type>::is_unsigned == true ); COMPILE_TIME_ASSERT( pixel_traits<typename out_image_type::type>::is_unsigned == true );
typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type in_image_basic_pixel_type;
COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) < sizeof(long));
typedef typename in_image_type::type in_pixel_type; typedef typename in_image_type::type in_pixel_type;
typedef typename out_image_type::type out_pixel_type; typedef typename out_image_type::type out_pixel_type;
......
...@@ -27,6 +27,7 @@ namespace dlib ...@@ -27,6 +27,7 @@ namespace dlib
- pixel_traits<typename out_image_type::type>::has_alpha == false - pixel_traits<typename out_image_type::type>::has_alpha == false
- pixel_traits<typename in_image_type::type>::is_unsigned == true - pixel_traits<typename in_image_type::type>::is_unsigned == true
- pixel_traits<typename out_image_type::type>::is_unsigned == true - pixel_traits<typename out_image_type::type>::is_unsigned == true
- pixel_traits<typename in_image_type::type>::max() < std::numeric_limits<long>::max()
ensures ensures
- #out_img == the histogram equalized version of in_img - #out_img == the histogram equalized version of in_img
- #out_img.nc() == in_img.nc() - #out_img.nc() == in_img.nc()
...@@ -49,6 +50,7 @@ namespace dlib ...@@ -49,6 +50,7 @@ namespace dlib
requires requires
- in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h
- pixel_traits<typename in_image_type::type>::is_unsigned == true - pixel_traits<typename in_image_type::type>::is_unsigned == true
- pixel_traits<typename in_image_type::type>::max() < std::numeric_limits<long>::max()
- hist must be capable of representing a column vector of length - hist must be capable of representing a column vector of length
pixel_traits<typename in_image_type>::max(). I.e. if R and C are nonzero pixel_traits<typename in_image_type>::max(). I.e. if R and C are nonzero
then they must be values that don't conflict with the previous sentence. then they must be values that don't conflict with the previous sentence.
......
...@@ -177,7 +177,7 @@ namespace dlib ...@@ -177,7 +177,7 @@ namespace dlib
- else - else
- #label_img[r][c] != 0 - #label_img[r][c] != 0
- if (img.size() != 0) then - if (img.size() != 0) then
- returns max(array_to_matrix(label_img))+1 - returns max(array_to_matrix(#label_img))+1
(i.e. returns a number one greater than the maximum blob id number, (i.e. returns a number one greater than the maximum blob id number,
this is the number of blobs found.) this is the number of blobs found.)
- else - else
......
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_RANDOMLY_COlOR_IMAGE_H__
#define DLIB_RANDOMLY_COlOR_IMAGE_H__
#include "randomly_color_image_abstract.h"
#include "../hash.h"
#include "../pixel.h"
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <typename T>
struct op_randomly_color_image : does_not_alias
{
op_randomly_color_image( const T& img_) : img(img_){}
const T& img;
const static long cost = 7;
const static long NR = 0;
const static long NC = 0;
typedef rgb_pixel type;
typedef const rgb_pixel const_ret_type;
typedef typename T::mem_manager_type mem_manager_type;
typedef row_major_layout layout_type;
const_ret_type apply (long r, long c ) const
{
const unsigned long gray = get_pixel_intensity(img[r][c]);
if (gray != 0)
{
const uint32 h = murmur_hash3(&gray, sizeof(gray));
rgb_pixel pix;
pix.red = static_cast<unsigned char>(h)%200 + 55;
pix.green = static_cast<unsigned char>(h>>8)%200 + 55;
pix.blue = static_cast<unsigned char>(h>>16)%200 + 55;
return pix;
}
else
{
// keep black pixels black
return rgb_pixel(0,0,0);
}
}
long nr () const { return img.nr(); }
long nc () const { return img.nc(); }
};
template <
typename image_type
>
const matrix_op<op_randomly_color_image<image_type> >
randomly_color_image (
const image_type& img
)
{
typedef op_randomly_color_image<image_type> op;
return matrix_op<op>(op(img));
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_RANDOMLY_COlOR_IMAGE_H__
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_H__
#ifdef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_H__
#include "randomly_color_image_abstract.h"
#include "../hash.h"
#include "../pixel.h"
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename image_type
>
const matrix_exp randomly_color_image (
const image_type& img
);
/*!
requires
- image_type is an implementation of array2d/array2d_kernel_abstract.h
- pixel_traits<image_type::type> must be defined
ensures
- randomly generates a mapping from gray level pixel values
to the RGB pixel space and then uses this mapping to create
a colored version of img. Returns a matrix which represents
this colored version of img.
- black pixels in img will remain black in the output image.
- The returned matrix will have the same dimensions as img.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_H__
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_SEGMENT_ImAGE_H__
#define DLIB_SEGMENT_ImAGE_H__
#include "segment_image_abstract.h"
#include "../algs.h"
#include <vector>
#include "../geometry.h"
#include "../disjoint_subsets.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace impl
{
struct graph_image_segmentation_data
{
graph_image_segmentation_data() : component_size(1), internal_diff(0) {}
unsigned long component_size;
unsigned short internal_diff;
};
template <typename T>
inline T edge_diff(
const T& a,
const T& b
)
{
if (a > b)
return a - b;
else
return b - a;
}
struct segment_image_edge_data
{
segment_image_edge_data (){}
segment_image_edge_data (
const rectangle& rect,
const point& p1,
const point& p2,
const unsigned short& diff_
) :
idx1(p1.y()*rect.width() + p1.x()),
idx2(p2.y()*rect.width() + p2.x()),
diff(diff_)
{}
unsigned long idx1;
unsigned long idx2;
unsigned short diff;
};
}
// ----------------------------------------------------------------------------------------
template <
typename in_image_type,
typename out_image_type
>
void segment_image (
const in_image_type& in_img,
out_image_type& out_img,
const unsigned long k = 200,
const unsigned long min_diff = 0
)
{
using namespace dlib::impl;
typedef typename in_image_type::type ptype;
// make sure requires clause is not broken
DLIB_ASSERT(is_same_object(in_img, out_img) == false,
"\t void segment_image()"
<< "\n\t The input images can't be the same object."
);
COMPILE_TIME_ASSERT(is_unsigned_type<ptype>::value && sizeof(ptype) <= 2);
COMPILE_TIME_ASSERT(is_unsigned_type<typename out_image_type::type>::value);
out_img.set_size(in_img.nr(), in_img.nc());
// don't bother doing anything if the image is too small
if (in_img.nr() < 2 || in_img.nc() < 2)
{
assign_all_pixels(out_img,0);
return;
}
disjoint_subsets sets;
sets.set_size(in_img.size());
std::vector<graph_image_segmentation_data> data(in_img.size());
std::vector<unsigned long> counts(std::numeric_limits<ptype>::max()+1, 0);
border_enumerator be(get_rect(in_img), 1);
// we are going to do a radix sort on the edge weights. So the first step
// is to accumulate them into count.
const rectangle area = get_rect(in_img);
while (be.move_next())
{
const long r = be.element().y();
const long c = be.element().x();
const ptype pix = in_img[r][c];
if (area.contains(c-1,r)) counts[edge_diff(pix, in_img[r ][c-1])] += 1;
if (area.contains(c+1,r)) counts[edge_diff(pix, in_img[r ][c+1])] += 1;
if (area.contains(c-1,r-1)) counts[edge_diff(pix, in_img[r-1][c-1])] += 1;
if (area.contains(c ,r-1)) counts[edge_diff(pix, in_img[r-1][c ])] += 1;
if (area.contains(c+1,r-1)) counts[edge_diff(pix, in_img[r-1][c+1])] += 1;
if (area.contains(c-1,r+1)) counts[edge_diff(pix, in_img[r+1][c-1])] += 1;
if (area.contains(c ,r+1)) counts[edge_diff(pix, in_img[r+1][c ])] += 1;
if (area.contains(c+1,r+1)) counts[edge_diff(pix, in_img[r+1][c+1])] += 1;
}
for (long r = 1; r+1 < in_img.nr(); ++r)
{
for (long c = 1; c+1 < in_img.nc(); ++c)
{
const ptype pix = in_img[r][c];
counts[edge_diff(pix, in_img[r ][c-1])] += 1;
counts[edge_diff(pix, in_img[r ][c+1])] += 1;
counts[edge_diff(pix, in_img[r-1][c-1])] += 1;
counts[edge_diff(pix, in_img[r-1][c ])] += 1;
counts[edge_diff(pix, in_img[r-1][c+1])] += 1;
counts[edge_diff(pix, in_img[r+1][c-1])] += 1;
counts[edge_diff(pix, in_img[r+1][c ])] += 1;
counts[edge_diff(pix, in_img[r+1][c+1])] += 1;
}
}
const unsigned long num_edges = shrink_rect(area,1).area()*8 + in_img.nr()*2*5 - 8 + (in_img.nc()-2)*2*5;
std::vector<segment_image_edge_data> sorted_edges(num_edges);
// integrate counts. The idea is to have sorted_edges[counts[i]] be the location that edges
// with an edge_diff of i go. So counts[0] == 0, counts[1] == number of 0 edge diff edges, etc.
unsigned long prev = counts[0];
for (unsigned long i = 1; i < counts.size(); ++i)
{
const unsigned long temp = counts[i];
counts[i] += counts[i-1];
counts[i-1] -= prev;
prev = temp;
}
counts[counts.size()-1] -= prev;
// now build a sorted list of all the edges
be.reset();
while(be.move_next())
{
const long r = be.element().y();
const long c = be.element().x();
const point p(c,r);
const ptype pix = in_img[r][c];
if (area.contains(c-1,r))
{
const ptype diff = edge_diff(pix, in_img[r ][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r),diff);
}
if (area.contains(c+1,r))
{
const ptype diff = edge_diff(pix, in_img[r ][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);
}
if (area.contains(c-1,r-1))
{
const ptype diff = edge_diff(pix, in_img[r-1][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r-1),diff);
}
if (area.contains(c ,r-1))
{
const ptype diff = edge_diff(pix, in_img[r-1][c ]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c ,r-1),diff);
}
if (area.contains(c+1,r-1))
{
const ptype diff = edge_diff(pix, in_img[r-1][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r-1),diff);
}
if (area.contains(c-1,r+1))
{
const ptype diff = edge_diff(pix, in_img[r+1][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r+1),diff);
}
if (area.contains(c ,r+1))
{
const ptype diff = edge_diff(pix, in_img[r+1][c ]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c ,r+1),diff);
}
if (area.contains(c+1,r+1))
{
const ptype diff = edge_diff(pix, in_img[r+1][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r+1),diff);
}
}
// same thing as the above loop but now we do it on the interior of the image and therefore
// don't have to include the boundary checking if statements used above.
for (long r = 1; r+1 < in_img.nr(); ++r)
{
for (long c = 1; c+1 < in_img.nc(); ++c)
{
const point p(c,r);
const ptype pix = in_img[r][c];
ptype diff;
diff = edge_diff(pix, in_img[r ][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r),diff);
diff = edge_diff(pix, in_img[r ][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);
diff = edge_diff(pix, in_img[r-1][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r-1),diff);
diff = edge_diff(pix, in_img[r-1][c ]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c ,r-1),diff);
diff = edge_diff(pix, in_img[r-1][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r-1),diff);
diff = edge_diff(pix, in_img[r+1][c-1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r+1),diff);
diff = edge_diff(pix, in_img[r+1][c ]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c ,r+1),diff);
diff = edge_diff(pix, in_img[r+1][c+1]);
sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r+1),diff);
}
}
// now start connecting blobs together to make a minimum spanning tree.
for (unsigned long i = 0; i < sorted_edges.size(); ++i)
{
const unsigned long idx1 = sorted_edges[i].idx1;
const unsigned long idx2 = sorted_edges[i].idx2;
unsigned long set1 = sets.find_set(idx1);
unsigned long set2 = sets.find_set(idx2);
if (set1 != set2)
{
const ptype diff = sorted_edges[i].diff;
const ptype tau1 = k/data[set1].component_size;
const ptype tau2 = k/data[set2].component_size;
const ptype mint = std::min(data[set1].internal_diff + tau1,
data[set2].internal_diff + tau2);
if (diff <= std::max<ptype>(mint,min_diff))
{
const unsigned long new_set = sets.merge_sets(set1, set2);
data[new_set].component_size = data[set1].component_size + data[set2].component_size;
data[new_set].internal_diff = diff;
}
}
}
unsigned long idx = 0;
for (long r = 0; r < out_img.nr(); ++r)
{
for (long c = 0; c < out_img.nc(); ++c)
{
out_img[r][c] = sets.find_set(idx++);
}
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_SEGMENT_ImAGE_H__
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_SEGMENT_ImAGE_ABSTRACT_H__
#ifdef DLIB_SEGMENT_ImAGE_ABSTRACT_H__
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename in_image_type,
typename out_image_type
>
void segment_image (
const in_image_type& in_img,
out_image_type& out_img,
const unsigned long k = 200,
const unsigned long min_diff = 0
);
/*!
requires
- in_image_type == an implementation of array2d/array2d_kernel_abstract.h
- out_image_type == an implementation of array2d/array2d_kernel_abstract.h
- in_image_type::type == an unsigned 8-bit or 16bit integer type.
- out_image_type::type == unsigned integer type
- is_same_object(in_img, out_img) == false
ensures
- Attempts to segment in_img into regions which have some visual consistency to them.
In particular, this function implements the algorithm described in the paper:
Efficient Graph-Based Image Segmentation by Felzenszwalb and Huttenlocher.
- #out_img.nr() == in_img.nr()
- #out_img.nc() == in_img.nc()
- for all valid r and c:
- #out_img[r][c] == an integer value indicating the identity of the segment
containing the pixel in_img[r][c].
- The k parameter is a measure used to influence how large the segment regions will
be. Larger k generally results in larger segments being produced. For a deeper
discussion of the k parameter you should consult the above referenced paper.
- Any neighboring segments with an edge between them with a pixel difference <= min_diff
will always be merged. So making min_diff bigger makes this algorithm more eager
to merge neighboring segments.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_SEGMENT_ImAGE_ABSTRACT_H__
...@@ -36,8 +36,8 @@ namespace dlib ...@@ -36,8 +36,8 @@ namespace dlib
- filter.nr() % 2 == 1 (i.e. must be odd) - filter.nr() % 2 == 1 (i.e. must be odd)
- filter.nc() % 2 == 1 (i.e. must be odd) - filter.nc() % 2 == 1 (i.e. must be odd)
ensures ensures
- Applies the given spatial filter to in_img and stores the result in out_img. Also - Applies the given spatial filter to in_img and stores the result in out_img (i.e.
divides each resulting pixel by scale. cross-correlates in_img with filter). Also divides each resulting pixel by scale.
- The intermediate filter computations will be carried out using variables of type EXP::type. - The intermediate filter computations will be carried out using variables of type EXP::type.
This is whatever scalar type is used inside the filter matrix. This is whatever scalar type is used inside the filter matrix.
- Pixel values are stored into out_img using the assign_pixel() function and therefore - Pixel values are stored into out_img using the assign_pixel() function and therefore
......
...@@ -59,6 +59,19 @@ namespace dlib ...@@ -59,6 +59,19 @@ namespace dlib
ASSERT_ARE_SAME_TYPE(helper,void); ASSERT_ARE_SAME_TYPE(helper,void);
}; };
// ----------------------------------------------------------------------------------------
template <typename T>
struct is_array2d : public default_is_kind_value
{
/*!
- if (T is an implementation of array2d/array2d_kernel_abstract.h) then
- is_array2d<T>::value == true
- else
- is_array2d<T>::value == false
!*/
};
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template <typename T> template <typename T>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "matrix/matrix_assign.h" #include "matrix/matrix_assign.h"
#include "matrix/matrix_la.h" #include "matrix/matrix_la.h"
#include "matrix/symmetric_matrix_cache.h" #include "matrix/symmetric_matrix_cache.h"
#include "matrix/matrix_conv.h"
#ifdef DLIB_USE_BLAS #ifdef DLIB_USE_BLAS
#include "matrix/matrix_blas_bindings.h" #include "matrix/matrix_blas_bindings.h"
......
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_CONV_H__
#define DLIB_MATRIx_CONV_H__
#include "matrix_conv_abstract.h"
#include "matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2, bool flip_m2 = false>
struct op_conv
{
op_conv( const M1& m1_, const M2& m2_) :
m1(m1_),
m2(m2_),
nr_(m1.nr()+m2.nr()-1),
nc_(m1.nc()+m2.nc()-1)
{
if (nr_ < 0 || m1.size() == 0 || m2.size() == 0)
nr_ = 0;
if (nc_ < 0 || m1.size() == 0 || m2.size() == 0)
nc_ = 0;
}
const M1& m1;
const M2& m2;
long nr_;
long nc_;
const static long cost = (M1::cost+M2::cost)*10;
const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR+M2::NR-1);
const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC+M2::NC-1);
typedef typename M1::type type;
typedef type const_ret_type;
typedef typename M1::mem_manager_type mem_manager_type;
typedef typename M1::layout_type layout_type;
const_ret_type apply (long r, long c) const
{
type temp = 0;
const long min_rr = std::max<long>(r-m2.nr()+1, 0);
const long max_rr = std::min<long>(m1.nr()-1, r);
const long min_cc = std::max<long>(c-m2.nc()+1, 0);
const long max_cc = std::min<long>(m1.nc()-1, c);
for (long rr = min_rr; rr <= max_rr; ++rr)
{
for (long cc = min_cc; cc <= max_cc; ++cc)
{
if (flip_m2)
temp += m1(rr,cc)*m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1);
else
temp += m1(rr,cc)*m2(r-rr,c-cc);
}
}
return temp;
}
long nr () const { return nr_; }
long nc () const { return nc_; }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
};
template <
typename M1,
typename M2
>
const matrix_op<op_conv<M1,M2> > conv (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv<M1,M2> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
template <
typename M1,
typename M2
>
const matrix_op<op_conv<M1,M2,true> > xcorr (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv<M1,M2,true> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2, bool flip_m2 = false>
struct op_conv_same
{
op_conv_same( const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),nr_(m1.nr()),nc_(m1.nc())
{
if (m1.size() == 0 || m2.size() == 0)
nr_ = 0;
if (m1.size() == 0 || m2.size() == 0)
nc_ = 0;
}
const M1& m1;
const M2& m2;
long nr_;
long nc_;
const static long cost = (M1::cost+M2::cost)*10;
const static long NR = M1::NR;
const static long NC = M1::NC;
typedef typename M1::type type;
typedef type const_ret_type;
typedef typename M1::mem_manager_type mem_manager_type;
typedef typename M1::layout_type layout_type;
const_ret_type apply (long r, long c) const
{
r += m2.nr()/2;
c += m2.nc()/2;
type temp = 0;
const long min_rr = std::max<long>(r-m2.nr()+1, 0);
const long max_rr = std::min<long>(m1.nr()-1, r);
const long min_cc = std::max<long>(c-m2.nc()+1, 0);
const long max_cc = std::min<long>(m1.nc()-1, c);
for (long rr = min_rr; rr <= max_rr; ++rr)
{
for (long cc = min_cc; cc <= max_cc; ++cc)
{
if (flip_m2)
temp += m1(rr,cc)*m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1);
else
temp += m1(rr,cc)*m2(r-rr,c-cc);
}
}
return temp;
}
long nr () const { return nr_; }
long nc () const { return nc_; }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
};
template <
typename M1,
typename M2
>
const matrix_op<op_conv_same<M1,M2> > conv_same (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv_same<M1,M2> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
template <
typename M1,
typename M2
>
const matrix_op<op_conv_same<M1,M2,true> > xcorr_same (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv_same<M1,M2,true> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2, bool flip_m2 = false>
struct op_conv_valid
{
op_conv_valid( const M1& m1_, const M2& m2_) :
m1(m1_),m2(m2_),
nr_(m1.nr()-m2.nr()+1),
nc_(m1.nc()-m2.nc()+1)
{
if (nr_ < 0 || nc_ <= 0 || m1.size() == 0 || m2.size() == 0)
nr_ = 0;
if (nc_ < 0 || nr_ <= 0 || m1.size() == 0 || m2.size() == 0)
nc_ = 0;
}
const M1& m1;
const M2& m2;
long nr_;
long nc_;
const static long cost = (M1::cost+M2::cost)*10;
const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR-M2::NR+1);
const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC-M2::NC+1);
typedef typename M1::type type;
typedef type const_ret_type;
typedef typename M1::mem_manager_type mem_manager_type;
typedef typename M1::layout_type layout_type;
const_ret_type apply (long r, long c) const
{
r += m2.nr()-1;
c += m2.nc()-1;
type temp = 0;
const long min_rr = std::max<long>(r-m2.nr()+1, 0);
const long max_rr = std::min<long>(m1.nr()-1, r);
const long min_cc = std::max<long>(c-m2.nc()+1, 0);
const long max_cc = std::min<long>(m1.nc()-1, c);
for (long rr = min_rr; rr <= max_rr; ++rr)
{
for (long cc = min_cc; cc <= max_cc; ++cc)
{
if (flip_m2)
temp += m1(rr,cc)*m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1);
else
temp += m1(rr,cc)*m2(r-rr,c-cc);
}
}
return temp;
}
long nr () const { return nr_; }
long nc () const { return nc_; }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
};
template <
typename M1,
typename M2
>
const matrix_op<op_conv_valid<M1,M2> > conv_valid (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv_valid<M1,M2> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
template <
typename M1,
typename M2
>
const matrix_op<op_conv_valid<M1,M2,true> > xcorr_valid (
const matrix_exp<M1>& m1,
const matrix_exp<M2>& m2
)
{
COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));
typedef op_conv_valid<M1,M2,true> op;
return matrix_op<op>(op(m1.ref(),m2.ref()));
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_MATRIx_CONV_H__
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