-
Notifications
You must be signed in to change notification settings - Fork 1
/
Image.h
328 lines (295 loc) · 12.2 KB
/
Image.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*********************** Image ****************************
* Image<T> class is a 2d array of any class T. Data are stored
* in a form that allows rapid iteration along rows, and a number of
* templates are provided that execute operations on all pixels or
* a subset of pixels in one or more images.
*
* Will be linked with Image.o from Image.cpp. Note that Image types
* float, int, and short are instantiated at end of Image.cpp. If you
* need other types, you'll have to add them there.
*
* Image is actually a handle that contains a pointer to an Header<T>
* structure ("header") and an ImageData<T> structure ("data"). Copy
* and assignment semantics are that a new Image refers to same data
* and header structures as the old one. Link counting insures deletion
* of the header & data structures when they become unused. To get a
* fresh deep copy of an Image, use Image::duplicate().
*
* The ImageData<T> class should never be needed by the user. It
* is used by FITSImage class (and maybe other disk image formats)
* that reads/writes Image objects from disk. ImageData does not
* allocate any memory when created with undefined Bounds.
*
* All specifications of pixel areas use Bounds<int> objects - see Bounds.h.
* Bounds<int>(x1,x2,y1,y2) is usual constructor, Bounds<int>() creates a
* null region.
*
* Image::subimage creates a new image that is contained within the original
* image AND SHARES ITS DATA. Deleting the parent Image before any
* of its derived subimages throws an exception.
*
* Iterators Image::iter and Image::const_iter are provided to traverse rows
* of images. These are only valid to traverse a row, going past end of
* row will give unpredictable results. Functions rowBegin() and rowEnd()
* give bounds for row iteration. getIter() gets iterator to arbitrary
* point.
* Range-checked iterators are ImageChk_iter and ImageChk_const_iter, which are
* also typedef'd as Image::checked_iter and checked_const_iter. Range-checked
* access is via Image::at() calls. Range-checked iterators are used for
* all calls if
* #define IMAGE_BOUNDS_CHECK
; * is compiled in.
*
* A const Image has read-only header and data access.
*
* Image constructors are:
* Image(ncol, nrows) makes new image with origin at (1,1)
* Image(Bounds<int>) makes new image with arbitrary row/col range
* Image(Bounds<int>, value) makes new image w/all pixels set to value.
* also a constructor directly from Header & ImageData structures,
* which should be used only by FITSImage or routines that build Images.
*
* You can access image elements with (int x, int y) syntax:
* theImage(4,12)=15.2;
* Many unary and binary arithmetic operations are supplied, with
* templates provided to build others quickly.
*
* If an image is locked, you will get an exception if you try to acquire a
* non-constant iterator or a reference to an element via overloaded operator(x,y).
* To avoid this, ask for ConstIterator and access elements via value(x,y).
* If Image instance is const, this is done automatically, whether Image is locked or not.
********/
#ifndef IMAGE_H
#define IMAGE_H
#include <algorithm>
#include <functional>
#include <list>
#include <sstream>
#include <typeinfo>
#include <string>
#include "Std.h"
#include "Bounds.h"
#include "Header.h"
namespace img {
// Exception classes:
class ImageError: public std::runtime_error {
public:
ImageError(const string &m=""): std::runtime_error("Image Error: " + m) {}
};
class ImageBounds: public ImageError {
public:
ImageBounds(const string &m=""):
ImageError("out of bounds " + m) {}
};
}
#include "ImageAlgorithms.h"
#include "Image2.h" //includes the classes not needed by end-user.
namespace img {
template <class T=float>
class Image {
private:
ImageData<T>* D; //pixel data
mutable int* dcount; // link count for the data structure
Header* H; //the header
mutable int* hcount;
public:
// Default constructor builds a null image:
explicit Image(const Bounds<int> inBounds=Bounds<int>()):
D(new ImageData<T>(inBounds)),
H(new Header()),
dcount(new int(1)),
hcount(new int(1)) {}
Image(const int ncol, const int nrow):
D(new ImageData<T>(Bounds<int>(1,ncol,1,nrow))),
H(new Header()),
dcount(new int(1)),
hcount(new int(1)) {}
explicit Image(const Bounds<int> inBounds, const T initValue):
D(new ImageData<T>(inBounds, initValue)),
H(new Header()),
dcount(new int(1)),
hcount(new int(1)) {}
// Copy constructor is really a data share; lock status is shared too.
Image(const Image &rhs):
D(rhs.D),
H(rhs.H),
dcount(rhs.dcount),
hcount(rhs.hcount) {(*dcount)++; (*hcount)++;}
// Same for assignment:
Image& operator=(const Image& rhs) {
if (&rhs == this) return *this;
if (D!=rhs.D) {
if (--(*dcount)==0) {delete D; delete dcount;}
D = rhs.D; dcount=rhs.dcount; (*dcount)++;
}
if (H!=rhs.H) {
if (--(*hcount)==0) {delete H; delete hcount;}
H = rhs.H; hcount=rhs.hcount; (*hcount)++;
}
return *this;
}
~Image() {
if (--(*dcount)==0) {delete D; delete dcount;}
if (--(*hcount)==0) {delete H; delete hcount;}
}
// Create new image with fresh copies of data & header. It will be unlocked, unchanged.
Image duplicate() const;
// New image that is subimage of this (shares pixels & header data and
// inherits the lock / change status of this).
Image subimage(const Bounds<int> bsub);
const Image subimage(const Bounds<int> bsub) const ;
////////////////////////////////////////////////////////////
// The following methods restructure the data array. They will throw an exception
// if this Image is a subimage or has extant subimages
//
// Make this image (or just data) be a duplicate of another's.
// All Images that refer to same data are changed.
void copyDataFrom(const Image& rhs) {D->copyFrom(*(rhs.D));}
void copyFrom(const Image& rhs) {
D->copyFrom(*(rhs.D));
*H = *(rhs.H);
}
// Resize the image.
// Note all Images sharing this ImageData will be affected.
// Data are destroyed in the process.
void resize(const Bounds<int> newBounds) {D->resize(newBounds);}
//
// Shift origin of image - same caveats apply as above
void shift(int x0, int y0) {D->shift(x0,y0);}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Routines here are not meant for general usage. They
// are for FitsImage to be able to manipulate guts of images.
// Create from a data and a header object: note that both will be
// deleted when this object is deleted unless [dh]count are given.
Image(ImageData<T>* Din, Header* Hin,
int* dc=new int(0),
int* hc=new int(0)): D(Din), H(Hin),
dcount(dc), hcount(hc) {(*dcount)++; (*hcount)++;}
const ImageData<T>* data() const {return D;}
////////////////////////////////////////////////////////////
// Header access and some shortcuts to keywords:
Header* header() {return H;}
const Header* header() const {return H;}
// Get/set the value of header records. Bool returns false if
// keyword doesn't exist or does not match type of argument.
template <class U>
bool getHdrValue(const string keyword, U& outVal) const {
return header()->getValue(keyword, outVal);
}
template <class U>
bool setHdrValue(const string keyword, const U& inVal) {
return header()->setValue(keyword,inVal);
}
// Locking and flagging changes:
// Note that alterations to subimages mark parents as changed.
// Clearing change flag clears subimages.
// locking parent locks subimages.
// Exception for attempt to clear change flag or lock a subimage.
bool isChanged() const {return H->isChanged() || D->isChanged();}
void clearChanged() {D->clearChanged(); H->clearChanged();}
bool isLocked() const {return H->isLocked() || D->isLocked();}
// Note ***there is no unlocking of data.*** This avoids having const objects change.
void setLock() {D->setLock(); H->setLock();}
// Element access
#ifdef IMAGE_BOUNDS_CHECK
// Element access is checked always
const T operator()(int xpos, int ypos) const {
return at(xpos,ypos);
}
T& operator()(int xpos, int ypos) {
return at(xpos,ypos);
}
// This routine is necessary for read access to a locked, non-const Image:
T value(int xpos, int ypos) const {
return at(xpos, ypos);
}
#else
// Unchecked access
const T operator()(const int xpos, const int ypos) const {
return D->value(xpos,ypos);
}
T& operator()(const int xpos, const int ypos) {
return (*D)(xpos,ypos);
}
// This routine is necessary for read access to a locked, non-const Image:
T value(int xpos, int ypos) const {
return D->value(xpos, ypos);
}
#endif
// Element access - explicitly checked
const T at(const int xpos, const int ypos) const {
return D->value_at(xpos,ypos);
}
T& at(const int xpos, const int ypos) {
return D->at(xpos,ypos);
}
const T value_at(const int xpos, const int ypos) const {
return D->value_at(xpos,ypos);
}
// iterators, rowBegin()/end()
typedef Chk_iterator<T> checked_iterator;
checked_iterator getCheckedIterator(const int x, const int y) {
return checked_iterator(D,x,y);
}
typedef Chk_const_iterator<T> checked_const_iterator;
checked_const_iterator getCheckedConstIterator(const int x, const int y) const {
return checked_const_iterator(D,x,y);
}
#ifdef IMAGE_BOUNDS_CHECK
typedef checked_iterator iterator;
typedef checked_const_iterator const_iterator;
iterator getIterator(const int x, const int y) {
return getCheckedIterator(x,y);}
const_iterator getConstIterator(const int x, const int y) const {
return getCheckedConstIterator(x,y); }
#else
typedef T* iterator;
typedef const T* const_iterator;
iterator getIterator(const int x, const int y) {
return D->location(x,y); }
const_iterator getConstIterator(const int x, const int y) const {
return D->const_location(x,y); }
#endif
iterator rowBegin(int r) {return getIterator(xMin(),r);}
const_iterator constRowBegin(int r) const {return getConstIterator(xMin(),r);}
iterator rowEnd(int r) {return getIterator(xMax()+1,r);}
const_iterator constRowEnd(int r) const {return getConstIterator(xMax()+1,r);}
const_iterator getIterator(const int x, const int y) const {
return getConstIterator(x,y); }
const_iterator rowBegin(int r) const {return constRowBegin(r);}
const_iterator rowEnd(int r) const {return constRowEnd(r);}
// bounds access functions
Bounds<int> getBounds() const {return D->getBounds();}
int xMin() const {return D->getBounds().getXMin();}
int xMax() const {return D->getBounds().getXMax();}
int yMin() const {return D->getBounds().getYMin();}
int yMax() const {return D->getBounds().getYMax();}
// Image/scalar arithmetic operations
void operator+=(T x) {transform_pixel(*this, bind2nd(plus<T>(),x));}
void operator-=(T x) {transform_pixel(*this, bind2nd(minus<T>(),x));}
void operator*=(T x) {transform_pixel(*this, bind2nd(multiplies<T>(),x));}
void operator/=(T x) {transform_pixel(*this, bind2nd(divides<T>(),x));}
void operator-() {transform_pixel(*this, negate<T>());}
class ConstReturn {
public:
ConstReturn(const T v): val(v) {}
T operator()(const T dummy) const {return val;}
private:
T val;
};
void operator=(const T val) {transform_pixel(*this, ConstReturn(val));}
// Image/Image arithmetic ops: rhs must be subset of this
void operator+=(const Image<T> rhs);
void operator-=(const Image<T> rhs);
void operator*=(const Image<T> rhs);
void operator/=(const Image<T> rhs);
// Image/Image arithmetic binops: bounds must match.
Image<T> operator+(const Image<T> rhs) const;
Image<T> operator-(const Image<T> rhs) const;
Image<T> operator*(const Image<T> rhs) const;
Image<T> operator/(const Image<T> rhs) const;
// ??? mixed-type arithmetic & conversions?
};
} //namespace img
#endif