1 #ifndef CVD_INCLUDE_MORPHOLOGY_H 2 #define CVD_INCLUDE_MORPHOLOGY_H 6 #include <cvd/vision.h> 7 #include <cvd/vision_exceptions.h> 14 #ifndef DOXYGEN_IGNORE_INTERNAL 17 namespace MorphologyHelpers
23 vector<ptrdiff_t> offsets(
const vector<ImageRef>& v,
const BasicImage<T>& s)
25 vector<ptrdiff_t> off;
27 for(
unsigned int i = 0; i < v.size(); i++)
28 off.push_back(v[i].x + v[i].y * s.row_stride() - 1);
33 vector<vector<ImageRef>> row_split(
const vector<ImageRef>& v,
int y_lo,
int y_hi);
77 template <
class Accumulator,
class T>
80 using Internal::MorphologyHelpers::offsets;
81 using Internal::MorphologyHelpers::row_split;
98 int x_lo = selem[0].x;
99 int x_hi = selem[0].x;
100 int y_lo = selem[0].y;
101 int y_hi = selem[0].y;
103 for(
unsigned int i = 0; i < selem.size(); i++)
105 x_lo = min(x_lo, selem[i].x);
106 x_hi = max(x_hi, selem[i].x);
107 y_lo = min(y_lo, selem[i].y);
108 y_hi = max(y_hi, selem[i].y);
113 vector<ImageRef> structure_element = selem;
114 vector<ImageRef> shifted;
116 sort(structure_element.begin(), structure_element.end());
117 for(
unsigned int i = 0; i < structure_element.size(); i++)
118 shifted.push_back(structure_element[i] +
ImageRef(1, 0));
120 vector<ImageRef> add,
remove;
121 set_difference(shifted.begin(), shifted.end(), structure_element.begin(), structure_element.end(), back_inserter(add));
122 set_difference(structure_element.begin(), structure_element.end(), shifted.begin(), shifted.end(), back_inserter(
remove));
127 vector<ptrdiff_t> add_off = offsets(add, in);
128 vector<ptrdiff_t> remove_off = offsets(
remove, in);
135 vector<vector<ImageRef>> split_selem = row_split(structure_element, y_lo, y_hi);
136 vector<vector<ImageRef>> split_add = row_split(add, y_lo, y_hi);
137 vector<vector<ImageRef>> split_remove = row_split(
remove, y_lo, y_hi);
141 if(x_hi - x_lo + 1 <= in.
size().x)
142 for(
int y = 0; y < in.
size().y; y++)
145 int startrow = max(0, -y_lo - y);
146 int endrow =
static_cast<int>(split_selem.size()) - max(0, y + y_hi - in.
size().y + 1);
149 int x_first_full = max(0, -x_lo);
150 int x_after_last_full = min(in.
size().x, in.
size().x - x_hi);
156 for(
int i = startrow; i < endrow; i++)
157 for(
int j = (
int)split_selem[i].size() - 1; j >= 0 && split_selem[i][j].x >= 0; j--)
158 acc.insert(in[y + split_selem[i][0].y][split_selem[i][j].x]);
160 out[y][0] = acc.get();
165 for(
int x = 1; x <= x_first_full; x++)
167 for(
int i = startrow; i < endrow; i++)
168 for(
int j = (
int)split_remove[i].size() - 1; j >= 0 && split_remove[i][j].x + x - 1 >= 0; j--)
169 acc.remove(in[y + split_remove[i][0].y][x + split_remove[i][j].x - 1]);
171 for(
int i = startrow; i < endrow; i++)
172 for(
int j = (
int)split_add[i].size() - 1; j >= 0 && split_add[i][j].x + x - 1 >= 0; j--)
173 acc.insert(in[y + split_add[i][0].y][x + split_add[i][j].x - 1]);
175 out[y][x] = acc.get();
181 int add_start = 0, add_end = 0, remove_start = 0, remove_end = 0;
182 for(
int i = 0; i < startrow; i++)
184 add_start +=
static_cast<int>(split_add[i].size());
185 remove_start +=
static_cast<int>(split_remove[i].size());
187 for(
int i = 0; i < endrow; i++)
189 add_end +=
static_cast<int>(split_add[i].size());
190 remove_end +=
static_cast<int>(split_remove[i].size());
194 for(
int x = max(0, -x_lo + 1); x < x_after_last_full; x++)
196 for(
int i = remove_start; i < remove_end; i++)
197 acc.remove(*(in[y] + x + remove_off[i]));
199 for(
int i = add_start; i < add_end; i++)
200 acc.insert(*(in[y] + x + add_off[i]));
202 out[y][x] = acc.get();
206 for(
int x = x_after_last_full; x < in.
size().x; x++)
208 for(
int i = startrow; i < endrow; i++)
209 for(
int j = 0; j < (int)split_remove[i].size() && split_remove[i][j].x + x - 1 < in.
size().x; j++)
210 acc.remove(in[y + split_remove[i][0].y][x + split_remove[i][j].x - 1]);
212 for(
int i = startrow; i < endrow; i++)
213 for(
int j = 0; j < (int)split_add[i].size() && split_add[i][j].x + x - 1 < in.
size().x; j++)
214 acc.insert(in[y + split_add[i][0].y][x + split_add[i][j].x - 1]);
216 out[y][x] = acc.get();
223 for(
int y = 0; y < in.
size().y; y++)
226 int startrow = max(0, -y_lo - y);
227 int endrow =
static_cast<int>(split_selem.size()) - max(0, y + y_hi - in.
size().y + 1);
233 for(
int i = startrow; i < endrow; i++)
234 for(
int j = 0; j < (int)split_selem[i].size(); j++)
236 int xp = split_selem[i][j].x;
237 if(xp >= 0 && xp < in.
size().x)
238 acc.insert(in[y + split_selem[i][0].y][xp]);
241 out[y][0] = acc.get();
244 for(
int x = 1; x < in.
size().x; x++)
246 for(
int i = startrow; i < endrow; i++)
247 for(
int j = 0; j < (int)split_remove[i].size(); j++)
249 int xp = x + split_remove[i][j].x - 1;
250 if(xp >= 0 && xp < in.
size().x)
251 acc.remove(in[y + split_add[i][0].y][xp]);
254 for(
int i = startrow; i < endrow; i++)
255 for(
int j = 0; j < (int)split_add[i].size(); j++)
257 int xp = x + split_add[i][j].x - 1;
258 if(xp >= 0 && xp < in.
size().x)
259 acc.insert(in[y + split_add[i][0].y][xp]);
262 out[y][x] = acc.get();
268 #ifndef DOXYGEN_IGNORE_INTERNAL 271 template <
class C,
class D>
276 template <
class C,
class D>
288 const std::vector<ImageRef>& s;
306 template <
class C,
class D>
332 template <
class T,
template <
class>
class Cmp>
336 std::map<T, int, Cmp<T>> pix;
343 void insert(
const T& t)
348 void remove(
const T& t)
355 typedef typename std::map<T, int, Cmp<T>>::iterator it;
357 for(it i = pix.begin(); i != pix.end();)
416 for(
int i = 0; i < 256; i++)
441 for(
int j = 0; j < 256; j++)
443 return static_cast<byte>(j);
458 for(
int j = 255; j >= 0; j--)
460 return static_cast<byte>(j);
491 int threshold = max(0, (
int)floor(total * ptile + .5) - 1);
493 for(
int j = 0; j < 255; j++)
498 return static_cast<byte>(j);
507 int threshold = max(0, (
int)floor(total * (1 - ptile) + .5) - 1);
509 for(
int j = 255; j > 0; j--)
514 return static_cast<byte>(j);
571 template <
class T =
bool>
583 template <
class T =
bool>
595 template <
class T =
bool>
611 T median4(T a, T b, T c, T d)
613 T v[4] = { a, b, c, d };
614 std::nth_element(v, v + 2, v + 4);
621 return median4(im[r][c], im[r][c + 1], im[r + 1][c], im[r + 1][c + 1]);
625 T median6(T a, T b, T c, T d, T e, T f)
627 T v[6] = { a, b, c, d, e, f };
628 std::nth_element(v, v + 3, v + 6);
635 return median6(im[r][c], im[r][c + 1], im[r][c + 2], im[r + 1][c], im[r + 1][c + 1], im[r + 1][c + 2]);
640 return median6(im[r][c], im[r][c + 1], im[r + 1][c], im[r + 1][c + 1], im[r + 2][c], im[r + 2][c + 1]);
645 #ifndef DOXYGEN_IGNORE_INTERNAL Input images have incompatible dimensions.
Definition: vision_exceptions.h:26
All classes and functions are within the CVD namespace.
Definition: argb.h:6
ImageRef size() const
What is the size of this image?
Definition: image.h:557
void threshold(BasicImage< T > &im, const T &minimum, const T &hi)
thresholds an image by setting all pixel values below a minimum to 0 and all values above to a given ...
Definition: vision.h:256
Class for performing greyscale dilation.
Definition: morphology.h:383
Class for performing binary dilation.
Definition: morphology.h:584
void resize(const ImageRef &size)
Resize the image (destroying the data).
Definition: image.h:731
A helper class for performing basic grayscale morphology on an image of bytes.
Definition: morphology.h:401
Class for performing percentile filtering of bytes.
Definition: morphology.h:470
Class for performing greyscale erosion.
Definition: morphology.h:376
ConstPointerType data() const
Returns the raw image data.
Definition: image.h:535
Class for performing binary morphology.
Definition: morphology.h:538
Definition: image_ref.h:29
unsigned char byte
An 8-bit datatype.
Definition: byte.h:8
Class for performing binary erosion.
Definition: morphology.h:572
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
A full image which manages its own data.
Definition: image.h:623
void morphology(const BasicImage< T > &in, const std::vector< ImageRef > &selem, const Accumulator &a_, BasicImage< T > &out)
Perform a morphological operation on the image.
Definition: morphology.h:78
A helper class for performing basic grayscale morphology on an image.
Definition: morphology.h:333
Class for performing percentile filtering.
Definition: morphology.h:390