├── .gitignore
├── LICENSE
├── README
├── adaptive_ggm.py
├── gaussian_gradient_magnitude.py
├── ggm_combine
├── README
├── curvecontrol.py
├── ggm_combine.yml
├── interactive.py
└── qt.py
└── hideregions2
├── Makefile
├── README
├── dm
├── Makefile
├── block.cc
├── block.hh
├── coord.cc
├── coord.hh
├── dataset.cc
├── dataset.hh
├── descriptor.cc
├── descriptor.hh
├── dm.hh
├── exception.hh
├── general.cc
├── general.hh
├── image.cc
├── image.hh
├── memimage.cc
├── memimage.hh
└── test.cc
└── hideregions2.cc
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | test.out
3 | *~
4 | *.a
5 | hideregions2/hideregions2
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This repository contains useful utilities for Gaussian gradient
2 | filtering of astronomical FITS images.
3 |
4 | The programs are described in
5 |
6 | A very deep Chandra view of metals, sloshing and feedback in the
7 | Centaurus cluster of galaxies, J.S. Sanders, A.C. Fabian, G.B. Taylor,
8 | H.R. Russell, K.M. Blundell, R.E.A. Canning, J. Hlavacek-Larrondo,
9 | S.A. Walker, C.K. Grimes, 2016, MNRAS, 457, 82
10 | http://adsabs.harvard.edu/abs/2016MNRAS.457...82S
11 |
12 | and
13 |
14 | Detecting edges in the X-ray surface brightness of galaxy clusters,
15 | J.S. Sanders, A.C. Fabian, H.R. Russell, S.A. Walker, K.M. Blundell,
16 | 2016, MNRAS, accepted, http://arxiv.org/abs/1605.02911
17 |
18 | and
19 |
20 | Studying the merging cluster Abell 3266 with eROSITA
21 | J.S. Sanders et al.
22 | 2021, A&A submitted, https://arxiv.org/abs/2106.14534
23 |
24 | All software is Copyright Jeremy Sanders and released under the GNU
25 | GPLv2+.
26 |
27 | gaussian_gradient_magnitude.py
28 | ------------------------------
29 |
30 | The main program is gaussian_gradient_magnitude.py. This utility
31 | applies the gaussian gradient magnitude filter to an input fits image,
32 | using a particular scale, sigma, in pixels.
33 |
34 | Requirements:
35 | - Python 3.x, astropy, scipy, numpy
36 |
37 | To run, type
38 |
39 | $ ./gaussian_gradient_magnitude.py in.fits out.fits sigma
40 |
41 | Where sigma is a floating point value >0
42 |
43 | hideregions2
44 | ------------
45 |
46 | This is a tool to cosmetically hide point sources in fits images. It
47 | fills point sources with random values from the surrounding pixel
48 | region. See hideregions2/README for details.
49 |
50 | ggm_combine
51 | -----------
52 |
53 | This is an interactive tool to combine fits images filtered on
54 | different scales. See ggm_combine/README for details.
55 |
56 | adaptive_ggm.py
57 | ---------------
58 |
59 | This is an automated script to compute the adaptive GGM (used in
60 | Sanders et al. 2021).
61 |
62 | The program relies on the installation of the contour binning package
63 |
64 | https://github.com/jeremysanders/contbin
65 |
66 | Which should be available in the current PATH or can be pointed to
67 | using the --contbin-dir=DIR option. contbin needs to be up to date to
68 | include the latest accumulate_counts program.
69 |
70 | The program takes as input a counts image to compute the smoothing
71 | scale. It then smooths this counts image (or an optional input image
72 | given by --image=FILENAME) using these smoothing scales. The optional
73 | input image is to allow background subtraction or other
74 | manipulation. The gradient is computed from the log of the smoothed
75 | image (or linear image by using --log=False). Please note that if the
76 | input image has negative values then taking the log will generate nan
77 | outputs.
78 |
79 | The program can also take an optional mask image. This should contain
80 | 0 values for regions to be masked out and 1 for included
81 | regions. There is a special value of -2 which causes a pixel to be
82 | excluded in the input but present in the output (the smoothing ignores
83 | this input pixel but calculates the smoothed image from the
84 | surrounding pixels), which is good for cosmetically hiding point
85 | sources.
86 |
87 | The smoothing signal to noise ratio (specified with --sn=VALUE) is the
88 | main input parameter. It is used to calculate the smoothing scale from
89 | the input counts image. At present the smoothing radius contains at
90 | least sn-squared counts. There is an intermediate generated file
91 | containing the smoothing scale (--scale=FILENAME) which contains the
92 | radius-squared in pixels of the smoothing scale (the radius is used as
93 | the Gaussian sigma when smoothing). There is a second intermediate
94 | file which is the smoothed image (specified using
95 | --smoothed=FILENAME).
96 |
97 | An example usage:
98 |
99 | $ ./adaptive_ggm.py --sn=32 cts.fits grad.fits
100 |
101 | The full set of arguments include:
102 |
103 | $ ./adaptive_ggm.py --help
104 | usage: adaptive_ggm.py [-h] [--image IMAGE] [--sn SN] [--log LOG] [--mask MASK] [--scale SCALE] [--smoothed SMOOTHED]
105 | [--threads THREADS] [--contbin-dir CONTBIN_DIR]
106 | counts output
107 |
108 | Adapive Gaussian gradient magnitude
109 |
110 | positional arguments:
111 | counts counts image filename
112 | output output image filename
113 |
114 | optional arguments:
115 | -h, --help show this help message and exit
116 | --image IMAGE optional image filename to apply smoothing to (uses counts if not set) (default: None)
117 | --sn SN Smoothing S/N ratio (default: 32)
118 | --log LOG Calculate log after smoothing (default: True)
119 | --mask MASK Mask image (optional) (default: None)
120 | --scale SCALE Intermediate scale map filename (default: scale.fits)
121 | --smoothed SMOOTHED Intermediate smoothed image filename (default: smoothed.fits)
122 | --threads THREADS Number of threads to use when smoothing (default: 4)
123 | --contbin-dir CONTBIN_DIR
124 | Override location of contour binning code (default: None)
125 |
--------------------------------------------------------------------------------
/adaptive_ggm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os.path
4 | import argparse
5 | import subprocess
6 |
7 | from astropy.io import fits
8 | import numpy as np
9 |
10 | def _escapeArgs(args):
11 | """Escape arguments for printing."""
12 | out = []
13 | for a in args:
14 | a = a.replace("'", r"\'")
15 | wrap = False
16 | for c in ' \t[]<>|()$"#!*?~&;':
17 | if c in a:
18 | wrap = True
19 | break
20 | if wrap:
21 | a = "'%s'" % a
22 | out.append(a)
23 | return ' '.join(out)
24 |
25 | def call(*args, **argsv):
26 | """Shortcut for running external programs."""
27 | if not argsv.get('silent', False):
28 | print("+", _escapeArgs(args))
29 | subprocess.check_call(args)
30 |
31 | def calcGradient(inimg, log):
32 | """Calculate gradient magnitude of input image."""
33 |
34 | if log:
35 | inimg = np.log10(inimg)
36 |
37 | gy = inimg[1:,:]-inimg[:-1,:]
38 | gx = inimg[:,1:]-inimg[:,:-1]
39 | gyc = 0.5*(gy[1:,:]+gy[:-1,:])
40 | gxc = 0.5*(gx[:,1:]+gx[:,:-1])
41 |
42 | gyc = np.pad(gyc, ((1,1),(0,0)))
43 | gxc = np.pad(gxc, ((0,0),(1,1)))
44 | grad = np.sqrt(gxc**2 + gyc**2)
45 |
46 | return grad
47 |
48 | def main():
49 |
50 | parser = argparse.ArgumentParser(
51 | description="Adapive Gaussian gradient magnitude",
52 | formatter_class=argparse.ArgumentDefaultsHelpFormatter)
53 | parser.add_argument('counts', help='counts image filename')
54 |
55 | parser.add_argument('--image', help='optional image filename to apply smoothing to (uses counts if not set)')
56 | parser.add_argument('--sn', type=float, default=32, help='Smoothing S/N ratio')
57 | parser.add_argument('--log', type=bool, default=True, help='Calculate log after smoothing')
58 | parser.add_argument('--mask', help='Mask image (optional)')
59 | parser.add_argument('--scale', help='Intermediate scale map filename', default='scale.fits')
60 | parser.add_argument('--smoothed', help='Intermediate smoothed image filename', default='smoothed.fits')
61 | parser.add_argument('--threads', type=int, default=4, help='Number of threads to use when smoothing')
62 | parser.add_argument('--contbin-dir', help='Override location of contour binning code')
63 |
64 | parser.add_argument('output', help='output image filename')
65 | args = parser.parse_args()
66 |
67 | # where to find program
68 | program = 'accumulate_counts'
69 | if args.contbin_dir:
70 | program = os.path.join(args.contbin_dir, program)
71 |
72 | # first calculate scale map
73 | print('* Calculating scale map')
74 | cargs = [
75 | args.counts,
76 | '--scale=%s' % args.scale,
77 | '--sn=%g' % args.sn,
78 | '--threads=%i' % args.threads,
79 | ]
80 | if args.mask:
81 | cargs.append('--mask=%s' % args.mask)
82 |
83 | call(program, *cargs)
84 |
85 | # now smooth input image (using input image of counts image)
86 | print('* Smoothing input image')
87 | inimage = args.image or args.counts
88 |
89 | cargs = [
90 | inimage,
91 | '--apply',
92 | '--scale=%s' % args.scale,
93 | '--applied=%s' % args.smoothed,
94 | '--threads=%i' % args.threads,
95 | '--gaussian',
96 | ]
97 | if args.mask:
98 | cargs.append('--mask=%s' % args.mask)
99 |
100 | call(program, *cargs)
101 |
102 | # get gradient
103 | print('* Calculating gradient')
104 | smf = fits.open(args.smoothed, 'readonly')
105 | smimg = smf[0].data
106 | grad = calcGradient(smimg, args.log)
107 | smf.close()
108 |
109 | # write to output filename (based on input image)
110 | inf = fits.open(inimage, 'readonly')
111 | inf[0].data = grad
112 | print('* Writing gradient image', args.output)
113 | inf.writeto(args.output, overwrite=True)
114 |
115 | if __name__ == '__main__':
116 | main()
117 |
--------------------------------------------------------------------------------
/gaussian_gradient_magnitude.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import os
5 | import argparse
6 |
7 | from astropy.io import fits
8 | import scipy.ndimage
9 | import numpy as N
10 |
11 | def run(infile, outfile, scale):
12 | f = fits.open(infile)
13 | img = f[0].data
14 |
15 | # convert to float if required
16 | if issubclass(img.dtype.type, N.integer):
17 | img = img.astype(N.float32)
18 |
19 | proc = scipy.ndimage.gaussian_gradient_magnitude(img, scale)
20 |
21 | f[0].data = proc
22 |
23 | try:
24 | os.unlink(outfile)
25 | except OSError:
26 | pass
27 |
28 | f.writeto(outfile)
29 |
30 | def main():
31 | parser = argparse.ArgumentParser(
32 | description="Gaussian gradient magnitude")
33 | parser.add_argument('inimage', help='input image')
34 | parser.add_argument('outimage', help='output image')
35 | parser.add_argument('scale', type=float, help='gaussian sigma (pixels)')
36 | args = parser.parse_args()
37 |
38 | run(args.inimage, args.outimage, args.scale)
39 |
40 | if __name__ == '__main__':
41 | main()
42 |
--------------------------------------------------------------------------------
/ggm_combine/README:
--------------------------------------------------------------------------------
1 | ggm_combine: Copyright Jeremy Sanders, released under the GPLv2+
2 |
3 | ggm_combine is a GUI tool for combining together GGM-filtered images
4 | with different scales. It presents a control for varying the scaling
5 | with radius for each input image. A checkbox for each image also
6 | allows scales to be switched on and off.
7 |
8 | Requirements: Python 2.7, PyQt4, numpy, pyfits, PyYaml, ds9
9 |
10 | The current implementation is VERY BASIC and USER-UNFRIENDLY, so
11 | please feel free to send improvements to the code.
12 |
13 | The user has to create a series of fits files with the GGM-filtered
14 | images which should be combined (e.g. using scales of
15 | sigma=1,2,4,8,16...)
16 |
17 | The user should then copy the template ggm_combine.yml. The file
18 | should be edited to set:
19 |
20 | - The central pixel (to measure radii from), based from 0
21 | - An optional chop range to speed up the interactive modification
22 | (note this can be enabled/disabled as necessary)
23 | - Output filename, written to while the program is used
24 | - List of input filenames, and scaling values
25 |
26 | To use the program
27 |
28 | # start an instance of ds9
29 | ds9 &
30 |
31 | # run the interactive GUI
32 | ./interactive.py input.yml &
33 |
34 | As the scaling radii and scales are modified, the output values are
35 | written to out-pars.yml. Rename this to something safe (and the output
36 | fits file) if you want to keep a particular set of parameters.
37 |
38 | To modify the number of radial points, the yml file has to be edited.
39 |
40 | Note that WCS is lost in the output file!
41 |
--------------------------------------------------------------------------------
/ggm_combine/curvecontrol.py:
--------------------------------------------------------------------------------
1 | from __future__ import division, print_function
2 |
3 | import itertools
4 | import qt
5 | import numpy as N
6 |
7 | class MarkerItem(qt.QGraphicsEllipseItem):
8 | def __init__(self, parent, x, y):
9 | qt.QGraphicsEllipseItem.__init__(self, qt.QRectF(-5, -5, 10, 10))
10 | self.setPos(x, y)
11 | self.setFlag(qt.QGraphicsItem.ItemIsMovable)
12 | self.parent = parent
13 |
14 | def mouseReleaseEvent(self, event):
15 | qt.QGraphicsEllipseItem.mouseReleaseEvent(self, event)
16 | self.parent.updatePosns()
17 |
18 | def posn(self):
19 | return self.pos().x(), self.pos().y()
20 |
21 | height = 80
22 | width = 400
23 |
24 | class CurveScene(qt.QGraphicsScene):
25 |
26 | changed = qt.pyqtSignal(object)
27 |
28 | def __init__(self, vals, *args):
29 | qt.QGraphicsScene.__init__(self)
30 |
31 | self.pathitem = qt.QGraphicsPathItem()
32 | self.addItem(self.pathitem)
33 | self.pathitem.setZValue(-1)
34 |
35 | self.ellipses = []
36 |
37 | #for i in xrange(10):
38 | # ell = MarkerItem(self, i*40, 40)
39 | # self.addItem(ell)
40 | # self.ellipses.append(ell)
41 |
42 | maxx = N.max(vals[0])
43 | maxy = N.max(vals[1])
44 | self.maxx = maxx
45 |
46 | for x, y in zip(*vals):
47 | e = MarkerItem(self, N.sqrt(x/maxx)*width, height-y/maxy*height)
48 | self.addItem(e)
49 | self.ellipses.append(e)
50 |
51 | self.addLine( qt.QLineF(qt.QPointF(0,0), qt.QPointF(width, 0)) )
52 | self.addLine( qt.QLineF(qt.QPointF(0,height), qt.QPointF(width,height)) )
53 |
54 | self.updatePosns()
55 |
56 | def updatePosns(self):
57 | xvals = []
58 | yvals = []
59 |
60 | for e in self.ellipses:
61 | x, y = e.posn()
62 | xvals.append( (x/width)**2*self.maxx )
63 | yvals.append( (height-y)/height )
64 |
65 | xvals = N.array(xvals)
66 | yvals = N.array(yvals)
67 |
68 | # draw line
69 | xpts = N.arange(0, width)
70 | xv = (xpts/width)**2*self.maxx
71 | yv = N.interp(xv, xvals, yvals)
72 | ypts = height-yv*height
73 |
74 | path = qt.QPainterPath()
75 | path.moveTo(qt.QPointF(xpts[0], ypts[0]))
76 | for x, y in zip(xpts[1:], ypts[1:]):
77 | path.lineTo(qt.QPointF(x,y))
78 | self.pathitem.setPath(path)
79 |
80 | # send results to main program
81 | self.changed.emit((xvals, yvals))
82 |
83 | class CurveView(qt.QGraphicsView):
84 |
85 | changed = qt.pyqtSignal(object)
86 |
87 | def __init__(self, vals, *args):
88 | qt.QGraphicsView.__init__(self, *args)
89 | self.scene = CurveScene(vals, self)
90 | self.setScene(self.scene)
91 |
92 | self.scene.changed.connect(self.changed)
93 |
--------------------------------------------------------------------------------
/ggm_combine/ggm_combine.yml:
--------------------------------------------------------------------------------
1 | image:
2 | # central pixel (from 0) to calculate radii from
3 | centre: [1659, 1449]
4 | chop:
5 | # to speed up combination, choose a pixel range below to chop the
6 | # input images, and set enable to True
7 | range: [980, 930, 2210, 1840]
8 | enable: False
9 |
10 | # output filename to write combined image
11 | outfilename: filtered.fits
12 |
13 | # these are the input scales to combine (any number are allowed)
14 |
15 | # each entry is
16 | # image filename (each needs to be the same size)
17 | # list of radii in pixels (increase as necessary)
18 | # weight factors for each radius position (same number as for radii)
19 |
20 | data:
21 | - filename: expcorr_total_nopts_ggm1.fits.gz
22 | weightrad: [0,20,40,80,160,320,640,1280]
23 | weightvals: [1,1,0,0,0,0,0,0]
24 | - filename: expcorr_total_nopts_ggm2.fits.gz
25 | weightrad: [0,20,40,80,160,320,640,1280]
26 | weightvals: [2,2,2,0,0,0,0,0]
27 | - filename: expcorr_total_nopts_ggm4.fits.gz
28 | weightrad: [0,20,40,80,160,320,640,1280]
29 | weightvals: [0,4,4,4,0,0,0,0]
30 | - filename: expcorr_total_nopts_ggm8.fits.gz
31 | weightrad: [0,20,40,80,160,320,640,1280]
32 | weightvals: [0,0,8,8,8,0,0,0]
33 | - filename: expcorr_total_nopts_ggm16.fits.gz
34 | weightrad: [0,20,40,80,160,320,640,1280]
35 | weightvals: [0,0,0,10,10,10,0,0]
36 | - filename: expcorr_total_nopts_ggm32.fits.gz
37 | weightrad: [0,20,40,80,160,320,640,1280]
38 | weightvals: [0,0,0,0,10,10,10,10]
39 |
--------------------------------------------------------------------------------
/ggm_combine/interactive.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from __future__ import division, print_function
4 |
5 | import sys
6 | import os
7 | import glob
8 | from random import choice
9 | from string import ascii_uppercase
10 | from math import floor
11 |
12 | import qt
13 | import yaml
14 | from astropy.io import fits
15 | from astropy.wcs import WCS
16 | from astropy.nddata import Cutout2D
17 | import numpy as N
18 |
19 | import curvecontrol
20 |
21 | def ds9xpa(img, hdr, filename=None):
22 | """Send data to ds9 via xpa."""
23 | if filename is None:
24 | tempfn = '/tmp/temp_xpa_%i.fits' % os.getpid()
25 | else:
26 | tempfn = filename
27 | try:
28 | os.unlink(filename)
29 | except OSError:
30 | pass
31 |
32 | hdu = fits.PrimaryHDU(header=hdr)
33 | hdu.data = img
34 |
35 | hdus = fits.HDUList([hdu])
36 | hdus.writeto(tempfn)
37 |
38 | os.system('xpaset ds9 fits < %s' % tempfn)
39 |
40 | if filename is None:
41 | os.unlink(tempfn)
42 |
43 | class ImageContainer:
44 | def __init__(self, pars):
45 |
46 | self.pars = dict(pars)
47 | self.images = []
48 | self.scales = []
49 | self.radii = []
50 | self.weights = []
51 |
52 | if 'chop' in pars['image'] and pars['image']['chop']['enable']:
53 | chop = pars['image']['chop']['range']
54 | else:
55 | chop = None
56 |
57 | xc, yc = pars['image']['centre']
58 | for i, d in enumerate(pars['data']):
59 | print('Loading', d['filename'])
60 | with fits.open(d['filename']) as f:
61 | image = f[0].data
62 | # build a wcs object the hacky way
63 | if i == 0:
64 | hdr = f[0].header
65 | w = WCS(naxis=2)
66 | w.wcs.crval = [hdr['CRVAL1'], hdr['CRVAL2']]
67 | w.wcs.cdelt = [hdr['CDELT1'], hdr['CDELT2']]
68 | w.wcs.crpix = [hdr['CRPIX1'], hdr['CRPIX2']]
69 | w.wcs.ctype = [hdr['CTYPE1'], hdr['CTYPE2']]
70 | if chop:
71 | dy = chop[3]-chop[1]
72 | dx = chop[2]-chop[0]
73 | x0 = floor((chop[0] + chop[2])/2)
74 | y0 = floor((chop[1] + chop[3])/2)
75 | image_cutout = Cutout2D(image, (x0, y0), (dy, dx), wcs=w)
76 | image = image_cutout.data
77 | if i == 0:
78 | new_w = image_cutout.wcs
79 | hdr = new_w.to_header()
80 | self.images.append(image)
81 |
82 | radii = N.array(d['weightrad'], dtype=N.float64)
83 | self.radii.append(radii)
84 | weightvals = N.array(d['weightvals'], dtype=N.float64)
85 | maxval = round(N.max(weightvals), 2)
86 | self.scales.append(maxval)
87 | self.weights.append(weightvals/maxval)
88 | # set the header, which will be used later when writing the file
89 | some_random_str = ''.join(choice(ascii_uppercase) for i in range(10))
90 | with open('tmp' + some_random_str, 'w') as f:
91 | hdr.totextfile(f, clobber=False)
92 |
93 | if chop:
94 | xc -= chop[0]
95 | yc -= chop[1]
96 |
97 | self.radiiimg = N.fromfunction(
98 | lambda y, x: N.sqrt((x-xc)**2+(y-yc)**2),
99 | self.images[0].shape)
100 |
101 | def writeOutputPars(self, filename):
102 |
103 | # update values in parameters
104 | for i, (r, w, s) in enumerate(zip(self.radii, self.weights, self.scales)):
105 | self.pars['data'][i]['weightrad'] = r.tolist()
106 | self.pars['data'][i]['weightvals'] = (w*s).tolist()
107 |
108 | print('pars', repr(self.pars))
109 |
110 | # write to output
111 | with open(filename, 'w') as fout:
112 | fout.write( yaml.dump(self.pars) )
113 |
114 | def filterAdd(self):
115 | """Combine input images using interpolation."""
116 |
117 | out = N.zeros(self.images[0].shape)
118 | for image, radii, weights, scale in zip(
119 | self.images, self.radii, self.weights, self.scales):
120 | if scale > 0:
121 | print(id(image))
122 | print('radii', radii)
123 | print('weights', weights)
124 | print('scale', scale)
125 |
126 | interpol = N.interp(self.radiiimg, radii, weights*scale)
127 | out += interpol*image
128 |
129 | maxval = N.max(out[N.isfinite(out)])
130 | out = out / maxval
131 | return out
132 |
133 | class Window(qt.QWidget):
134 | def __init__(self, infile):
135 | qt.QWidget.__init__(self)
136 | layout = qt.QGridLayout()
137 |
138 | # load parameters
139 | with open(infile) as f:
140 | self.pars = pars = yaml.load(f)
141 |
142 | self.images = ImageContainer(pars)
143 |
144 | def getOnChanged(idx):
145 | def func(vals):
146 | self.images.radii[idx] = vals[0]
147 | self.images.weights[idx] = vals[1]
148 | self.redraw()
149 | return func
150 |
151 | def getEditChanged(cntrl, idx):
152 | def func():
153 | text = cntrl.text()
154 | try:
155 | self.images.scales[idx] = float(text)
156 | except ValueError:
157 | cntrl.setText(str(self.images.scales[idx]))
158 | return
159 | self.redraw()
160 | return func
161 |
162 | def getCheck(idx, cntrl):
163 | def func():
164 | self.images.scales[idx] = -self.images.scales[idx]
165 | cntrl.setText(str(self.images.scales[idx]))
166 | self.redraw()
167 | return func
168 |
169 | for i in range(len(self.images.images)):
170 |
171 | radii = self.images.radii[i]
172 | weights = self.images.weights[i]
173 | print('r', radii)
174 | print('w', weights)
175 |
176 | cntrl = curvecontrol.CurveView([radii, weights])
177 | cntrl.changed.connect( getOnChanged(i) )
178 | layout.addWidget(cntrl, i, 0)
179 |
180 | l = qt.QLineEdit()
181 | l.setText(str(self.images.scales[i]))
182 | l.editingFinished.connect( getEditChanged(l, i) )
183 | layout.addWidget(l, i, 1)
184 |
185 | c = qt.QCheckBox()
186 | c.clicked.connect( getCheck(i, l) )
187 | layout.addWidget(c, i, 2)
188 |
189 | self.setLayout(layout)
190 | self.redraw()
191 |
192 | def redraw(self):
193 | img = self.images.filterAdd()
194 | tmp_file = max(glob.iglob('tmp*'), key=os.path.getctime)
195 | print('Temporary header file: %s.' % tmp_file)
196 | hdr = fits.Header.fromtextfile(tmp_file)
197 | ds9xpa(img, hdr, filename=self.pars['image']['outfilename'])
198 | self.images.writeOutputPars('out-pars.yml')
199 |
200 | def main():
201 | filename = sys.argv[1]
202 |
203 | app = qt.QApplication(sys.argv)
204 | win = Window(filename)
205 | win.show()
206 | app.exec_()
207 |
208 | if __name__ == '__main__':
209 | main()
210 |
--------------------------------------------------------------------------------
/ggm_combine/qt.py:
--------------------------------------------------------------------------------
1 | """A convenience module to import both the used Qt symbols from."""
2 |
3 | import sip
4 | sip.setapi('QDate', 2)
5 | sip.setapi('QDateTime', 2)
6 | sip.setapi('QString', 2)
7 | sip.setapi('QTextStream', 2)
8 | sip.setapi('QTime', 2)
9 | sip.setapi('QUrl', 2)
10 | sip.setapi('QVariant', 2)
11 |
12 | from PyQt4.QtCore import *
13 | from PyQt4.QtGui import *
14 | from PyQt4.uic import loadUi
15 |
--------------------------------------------------------------------------------
/hideregions2/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | CC=g++
3 |
4 | CXXFLAGS=-g -Wall -O2
5 |
6 | ALL_CXXFLAGS = -I. -I${ASCDS_LIB}/../include $(CXXFLAGS)
7 |
8 | .cc.o:
9 | $(CXX) -c $(CPPFLAGS) $(ALL_CXXFLAGS) $<
10 |
11 | all: hideregions2
12 |
13 | clean:
14 | rm -f hideregions2 *.o
15 | @${MAKE} -C dm clean
16 |
17 | dm/libdmxx.a:
18 | @${MAKE} -C dm
19 |
20 | hideregions2: hideregions2.o dm/libdmxx.a
21 | $(CXX) -o hideregions2 hideregions2.o -Ldm -ldmxx -L$(ASCDS_LIB) -lregion -lascdm -Wl,-rpath $(ASCDS_LIB) -Wl,-rpath $(ASCDS_LIB)/../ots/lib
22 |
--------------------------------------------------------------------------------
/hideregions2/README:
--------------------------------------------------------------------------------
1 | hideregions2: Tool to fill in point sources with random values from
2 | the surrounding pixels. It's only tested for Chandra images.
3 |
4 | Copyright Jeremy Sanders, released under the GPLv2+.
5 |
6 | hideregions2 is a C++ code which links against the CIAO region
7 | libraries. It uses a C++ wrapper library to CIAO (dmxx).
8 |
9 | Requirements for building:
10 | - Chandra CIAO environment running
11 | - C++ compiler (only gcc g++ tested)
12 | - Boost library
13 |
14 | To build inspect the Makefile (and dm/Makefile) and run
15 |
16 | # make all
17 |
18 | If all went well, you'll have a hideregions2 executable.
19 |
20 | To use, run
21 |
22 | # hideregions2 in.fits points.reg out.fits
23 |
24 | Note that points.reg must be a CIAO region file in PHYSICAL
25 | COORDINATES. Only circle and ellipse regions are supported!
26 |
27 | WCS data are lost in the output file!
28 |
29 |
--------------------------------------------------------------------------------
/hideregions2/dm/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | CXXFLAGS = -g -Wall -I$(ASCDS_LIB)/../include/ -O2
3 |
4 | objects = dataset.o general.o descriptor.o image.o block.o memimage.o coord.o
5 |
6 | all: libdmxx.a test.out
7 |
8 | clean:
9 | rm -f *.o libdmxx.a
10 |
11 | dataset.o: dataset.hh image.hh block.hh
12 | general.o: general.hh
13 | descriptor.o: descriptor.hh
14 | image.o: image.hh descriptor.hh block.hh memimage.hh
15 | block.o: block.hh
16 | memimage.o: memimage.hh
17 | coord.o: coord.hh
18 |
19 | libdmxx.a: $(objects)
20 | ar -rcs libdmxx.a $(objects)
21 |
22 | test.out : test.cc libdmxx.a
23 | $(CXX) -o test.out test.cc $(CXXFLAGS) -L. -ldmxx -L$(ASCDS_LIB) \
24 | -lascdm -lregion
25 |
--------------------------------------------------------------------------------
/hideregions2/dm/block.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include "block.hh"
3 |
4 | dm::block::~block()
5 | {
6 | if ( m_block != 0 )
7 | dmBlockClose(m_block);
8 | }
9 |
10 | bool dm::block::read_key(const std::string& name, double* ret)
11 | {
12 | assert( m_block != 0 );
13 |
14 | dmDescriptor* desc = dmKeyRead_d(m_block, const_cast(name.c_str()),
15 | ret);
16 |
17 | return( desc != 0 );
18 | }
19 |
--------------------------------------------------------------------------------
/hideregions2/dm/block.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_BLOCK_HH
2 | #define DM_BLOCK_HH
3 |
4 | #include
5 | #include
6 |
7 | namespace dm {
8 |
9 | class block
10 | {
11 | public:
12 | virtual ~block();
13 |
14 | // read a double key with name, return false if not found
15 | bool read_key(const std::string& name, double* ret);
16 |
17 | protected:
18 | block(dmBlock *init) { m_block = init; }
19 |
20 | friend class dataset;
21 |
22 | private:
23 | block(const block& other); // disallow copy usage
24 | block& operator=(const block& other); // disallow =
25 |
26 | protected:
27 | dmBlock* m_block;
28 | };
29 |
30 |
31 | }
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/hideregions2/dm/coord.cc:
--------------------------------------------------------------------------------
1 | #include "coord.hh"
2 |
3 | dm::coord::coord(dmDescriptor *descr)
4 | : _descr(descr)
5 | {
6 | }
7 |
8 | dm::coord::~coord()
9 | {
10 | }
11 |
--------------------------------------------------------------------------------
/hideregions2/dm/coord.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_COORD_HH
2 | #define DM_COORD_HH
3 |
4 | #include
5 |
6 | namespace dm
7 | {
8 |
9 | class coord
10 | {
11 | public:
12 | protected:
13 | coord(dmDescriptor* descr);
14 | ~coord();
15 |
16 | private:
17 | dmDescriptor* _descr;
18 | };
19 |
20 |
21 | }
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/hideregions2/dm/dataset.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "dataset.hh"
5 | #include "exception.hh"
6 |
7 | //////////////////////////////////////////////////////////////////
8 | // Constructors / destructors
9 |
10 | dm::dataset::dataset(const std::string& filename, open_mode mode)
11 | : m_delete_on_finish(false)
12 | {
13 | strlike bfr(filename);
14 |
15 | switch( mode ) {
16 | case open:
17 | m_dataset = dmDatasetOpen( bfr() );
18 | if( m_dataset == 0 ) {
19 | except_unable_to_open e;
20 | e.set_descr(std::string("Unable to open file ") + filename);
21 | throw e;
22 | }
23 | break;
24 | case openrw:
25 | m_dataset = dmDatasetOpenUpdate( bfr() );
26 | if( m_dataset == 0 ) {
27 | except_unable_to_open e;
28 | e.set_descr(std::string("Unable to open file ") + filename +
29 | " (r/w access)");
30 | throw e;
31 | }
32 | break;
33 | case create_over:
34 | unlink(filename.c_str());
35 | case create:
36 | m_dataset = dmDatasetCreate( bfr() );
37 | if( m_dataset == 0 ) {
38 | except_unable_to_create e;
39 | e.set_descr(std::string("Unable to create file ") + filename);
40 | throw e;
41 | }
42 | break;
43 | }
44 | }
45 |
46 | dm::dataset::~dataset()
47 | {
48 | if( m_delete_on_finish )
49 | dmDatasetDelete( m_dataset );
50 | else
51 | dmDatasetClose( m_dataset );
52 | }
53 |
54 |
55 | ///////////////////////////////////////////////////////////////
56 | // Block functions
57 |
58 | int dm::dataset::get_current_block()
59 | {
60 | return dmDatasetGetCurrentBlockNo(m_dataset);
61 | }
62 |
63 | int dm::dataset::get_no_blocks()
64 | {
65 | return dmDatasetGetNoBlocks(m_dataset);
66 | }
67 |
68 | dm::block* dm::dataset::get_block(int blockno)
69 | {
70 | return new block( _get_block(blockno) );
71 | }
72 |
73 | std::string dm::dataset::get_block_name(int blockno)
74 | {
75 | char buffer[256];
76 | dmErrCode ret = dmDatasetGetBlockName(m_dataset, blockno, buffer, 255);
77 | if( ret != dmSUCCESS ) {
78 | except_invalid_param e;
79 | e.set_descr(std::string("Invalid block number ") +
80 | to_str(blockno));
81 | throw e;
82 | }
83 | return buffer;
84 | }
85 |
86 | dmBlockType dm::dataset::get_block_type(int blockno)
87 | {
88 | return dmDatasetGetBlockType(m_dataset, blockno);
89 | }
90 |
91 | dm::block* dm::dataset::copy_block(const std::string& name,
92 | const dm::block* parent,
93 | bool copydata)
94 | {
95 | strlike buffer(name);
96 |
97 | dmBlock* b = dmBlockCreateCopy(m_dataset, buffer(), parent->m_block,
98 | copydata);
99 |
100 | if( b == 0 ) {
101 | except_copy_fail e;
102 | e.set_descr("Unable to copy block");
103 | throw e;
104 | }
105 |
106 | return new block(b);
107 | }
108 |
109 | //////////////////////////////////////////////////////////////
110 | // Image functions
111 |
112 | dm::image* dm::dataset::create_image(const std::string& name,
113 | dmDataType datatype,
114 | const std::vector& axes_lengths)
115 | {
116 | strlike buffer(name);
117 |
118 | const unsigned noaxes = axes_lengths.size();
119 | long* lengths = new long[noaxes];
120 | for(unsigned i=0; i
5 | #include
6 | #include
7 |
8 | #include "general.hh"
9 | #include "block.hh"
10 | #include "image.hh"
11 |
12 | namespace dm
13 | {
14 |
15 | class dataset
16 | {
17 | public:
18 | // open the dataset (or create)
19 | dataset(const std::string& filename, open_mode mode = open);
20 | // close the dataset
21 | ~dataset();
22 |
23 | // BLOCK FUNCTIONS
24 | //////////////////
25 | // get current block no.
26 | int get_current_block();
27 | // get number of blocks
28 | int get_no_blocks();
29 | // move to block
30 | block* get_block(int blockno);
31 | // get the name of the numbered block
32 | std::string get_block_name(int blockno);
33 | // get type of the block
34 | dmBlockType get_block_type(int blockno);
35 | // copy block
36 | block* copy_block(const std::string& name, const block* parent,
37 | bool copydata);
38 |
39 | // IMAGE FUNCTIONS
40 | //////////////////
41 | image* create_image(const std::string& name,
42 | dmDataType datatype,
43 | const std::vector& axes_lengths);
44 | image* create_image(const std::string& name,
45 | dmDataType datatype,
46 | unsigned nlen, const int* lengths);
47 | image* create_image(const std::string& name,
48 | dmDataType datatype, int xw, int yw);
49 | image* get_image(int block_no = 1);
50 |
51 | // delete the dataset when we close (default false)
52 | void delete_when_finished(bool b=true)
53 | { m_delete_on_finish = b; }
54 |
55 | public:
56 | // static functions
57 | static void delete_on_disk(const std::string& filename);
58 |
59 | private:
60 | dataset(const dataset& other); // disallow copy
61 | dataset& operator=(const dataset& other); // disallow =
62 |
63 | dmBlock* _get_block(int blockno);
64 |
65 | private:
66 | dmDataset* m_dataset;
67 | bool m_delete_on_finish;
68 | };
69 |
70 |
71 |
72 | }
73 |
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/hideregions2/dm/descriptor.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "descriptor.hh"
4 | #include "general.hh"
5 | #include "exception.hh"
6 |
7 | dm::descriptor::descriptor(dmDescriptor* d)
8 | {
9 | m_descriptor = d;
10 | m_dtype = dmGetDataType(d);
11 | }
12 |
13 | template void
14 | dm::descriptor::set_pixel(const pix_vec& pos, T val)
15 | {
16 | arraycopy a( pos );
17 |
18 | int r;
19 | switch( get_data_type() ) {
20 | case dmSHORT:
21 | r = dmImageDataSetPixel_s(m_descriptor, a(), short(val) ); break;
22 | case dmLONG:
23 | r = dmImageDataSetPixel_l(m_descriptor, a(), long(val) ); break;
24 | case dmFLOAT:
25 | r = dmImageDataSetPixel_f(m_descriptor, a(), float(val) ); break;
26 | case dmDOUBLE:
27 | r = dmImageDataSetPixel_d(m_descriptor, a(), double(val) ); break;
28 | case dmBYTE:
29 | r = dmImageDataSetPixel_ub(m_descriptor, a(), (unsigned char)(val) ); break;
30 | case dmUSHORT:
31 | r = dmImageDataSetPixel_us(m_descriptor, a(), (unsigned short)(val) ); break;
32 | case dmULONG:
33 | r = dmImageDataSetPixel_ul(m_descriptor, a(), (unsigned long)(val) ); break;
34 | default:
35 | except_unknown e;
36 | e.set_descr("Invalid data type in dm::descriptor::set_pixel()");
37 | throw e;
38 | }
39 |
40 | if( r == dmFAILURE ) {
41 | except_invalid_param e;
42 | e.set_descr("Invalid return from dmImageDataSetPixel_x");
43 | throw e;
44 | }
45 | }
46 |
47 | template void
48 | dm::descriptor::get_pixel(const pix_vec& pos, T* val)
49 | {
50 | arraycopy a( pos );
51 |
52 | const long dim = pos.size();
53 |
54 | switch( get_data_type() ) {
55 | case dmSHORT:
56 | *val = T( dmImageDataGetPixel_s(m_descriptor, a(), dim ) ); break;
57 | case dmLONG:
58 | *val = T( dmImageDataGetPixel_l(m_descriptor, a(), dim ) ); break;
59 | case dmFLOAT:
60 | *val = T( dmImageDataGetPixel_f(m_descriptor, a(), dim ) ); break;
61 | case dmDOUBLE:
62 | *val = T( dmImageDataGetPixel_d(m_descriptor, a(), dim ) ); break;
63 | case dmBYTE:
64 | *val = T( dmImageDataGetPixel_ub(m_descriptor, a(), dim ) ); break;
65 | case dmUSHORT:
66 | *val = T( dmImageDataGetPixel_us(m_descriptor, a(), dim ) ); break;
67 | case dmULONG:
68 | *val = T( dmImageDataGetPixel_ul(m_descriptor, a(), dim ) ); break;
69 | default:
70 | except_unknown e;
71 | e.set_descr("Invalid data type in dm::descriptor::get_pixel()");
72 | throw e;
73 | }
74 | }
75 |
76 | namespace dm{
77 | // copies T2[] to T1 (size items)
78 | template void _translate_array(T1* a, T2* b, unsigned size)
79 | {
80 | for(unsigned i=0; i void
115 | dm::descriptor::get_subarray(const pix_vec& lowerbounds,
116 | const pix_vec& upperbounds,
117 | T** val)
118 | {
119 | const int size = get_total_size(lowerbounds, upperbounds);
120 | arraycopy l( lowerbounds), u ( upperbounds );
121 | *val = new T[size];
122 |
123 | int r;
124 | switch( get_data_type() ) {
125 | case dmSHORT: DM_DESCRIPTOR_GETSUBARRAY(short, _s);
126 | case dmLONG: DM_DESCRIPTOR_GETSUBARRAY(long, _l);
127 | case dmFLOAT: DM_DESCRIPTOR_GETSUBARRAY(float, _f);
128 | case dmDOUBLE: DM_DESCRIPTOR_GETSUBARRAY(double, _d);
129 | case dmBYTE: DM_DESCRIPTOR_GETSUBARRAY(unsigned char, _ub);
130 | case dmUSHORT: DM_DESCRIPTOR_GETSUBARRAY(unsigned short, _us);
131 | case dmULONG: DM_DESCRIPTOR_GETSUBARRAY(unsigned long, _ul);
132 | default:
133 | except_unknown e;
134 | e.set_descr("Invalid data type in dm::descriptor::get_subarray()");
135 | throw e;
136 | }
137 |
138 | if( r != dmSUCCESS ) {
139 | except_invalid_param e;
140 | e.set_descr("Invalid return from dmImageDataGetSubArray_x");
141 | throw e;
142 | }
143 | }
144 |
145 | #undef DM_DESCRIPTOR_GETSUBARRAY
146 |
147 | #define DM_DESCRIPTOR_SETSUBARRAY(TYPE, EXTEN) \
148 | {\
149 | TYPE *x = new TYPE[size];\
150 | _translate_array(x, val, size);\
151 | r = dmImageDataSetSubArray ## EXTEN (m_descriptor, l(), u(), x);\
152 | delete[] x; break;\
153 | }
154 |
155 | template void
156 | dm::descriptor::set_subarray(const pix_vec& lowerbounds,
157 | const pix_vec& upperbounds,
158 | const T* val)
159 | {
160 | const int size = get_total_size(lowerbounds, upperbounds);
161 | arraycopy l( lowerbounds), u ( upperbounds );
162 |
163 | int r;
164 | switch( get_data_type() ) {
165 | case dmSHORT: DM_DESCRIPTOR_SETSUBARRAY(short, _s);
166 | case dmLONG: DM_DESCRIPTOR_SETSUBARRAY(long, _l);
167 | case dmFLOAT: DM_DESCRIPTOR_SETSUBARRAY(float, _f);
168 | case dmDOUBLE: DM_DESCRIPTOR_SETSUBARRAY(double, _d);
169 | case dmBYTE: DM_DESCRIPTOR_SETSUBARRAY(unsigned char, _ub);
170 | case dmUSHORT: DM_DESCRIPTOR_SETSUBARRAY(unsigned short, _us);
171 | case dmULONG: DM_DESCRIPTOR_SETSUBARRAY(unsigned long, _ul);
172 | default:
173 | except_unknown e;
174 | e.set_descr("Invalid data type in dm::descriptor::set_subarray()");
175 | throw e;
176 | }
177 |
178 | if( r != dmSUCCESS ) {
179 | except_invalid_param e;
180 | e.set_descr("Invalid return from dmImageDataSetSubArray_x");
181 | throw e;
182 | }
183 | }
184 |
185 | #undef DM_DESCRIPTOR_SETSUBARRAY
186 |
187 | ///////////////////////////////////////////////////////////////////
188 |
189 | unsigned dm::descriptor::get_dimensionality()
190 | {
191 | return dmGetArrayDim( m_descriptor );
192 | }
193 |
194 | void dm::descriptor::get_dimensions(pix_vec* retn)
195 | {
196 | retn->clear();
197 |
198 | long *axeslengths = 0;
199 |
200 | const int no = dmGetArrayDimensions(m_descriptor, &axeslengths);
201 |
202 | for(int i=0; ipush_back( unsigned(axeslengths[i]) );
204 |
205 | std::free( axeslengths );
206 | }
207 |
208 | /////////////////////////////////////////////////////////////////////////
209 | // put these into the object output
210 | #define DM_DEFINE_SET_PIXEL(TYPE) \
211 | template void \
212 | descriptor::set_pixel(const pix_vec&, TYPE);\
213 | template void \
214 | descriptor::get_pixel(const pix_vec&, TYPE*);\
215 | template void \
216 | descriptor::get_subarray(const pix_vec&, const pix_vec&, TYPE**);\
217 | template void \
218 | descriptor::set_subarray(const pix_vec&, const pix_vec&, const TYPE*);
219 |
220 |
221 | namespace dm {
222 | DM_DEFINE_SET_PIXEL(short)
223 | DM_DEFINE_SET_PIXEL(long)
224 | DM_DEFINE_SET_PIXEL(float)
225 | DM_DEFINE_SET_PIXEL(double)
226 | DM_DEFINE_SET_PIXEL(unsigned char)
227 | DM_DEFINE_SET_PIXEL(unsigned short)
228 | DM_DEFINE_SET_PIXEL(unsigned long)
229 | }
230 |
231 | #undef DM_DEFINE_SET_PIXEL
232 |
--------------------------------------------------------------------------------
/hideregions2/dm/descriptor.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_DESCRIPTOR_HH
2 | #define DM_DESCRIPTOR_HH
3 |
4 | #include
5 | #include
6 |
7 | #include "general.hh"
8 |
9 | namespace dm
10 | {
11 |
12 | class descriptor
13 | {
14 | public:
15 | ~descriptor() {};
16 | descriptor(dmDescriptor *d);
17 |
18 | // allowed T classes are: long, short, float, double, unsigned char,
19 | // unsigned short, unsigned long
20 | template void set_pixel(const pix_vec& pos, T val);
21 | template void get_pixel(const pix_vec& pos, T* val);
22 | // get_subarray allocates the necessary space, returning *val
23 | template void get_subarray(const pix_vec& lowerbounds,
24 | const pix_vec& upperbounds,
25 | T** val);
26 | template void set_subarray(const pix_vec& lowerbounds,
27 | const pix_vec& upperbounds,
28 | const T* val);
29 |
30 | unsigned get_dimensionality();
31 | void get_dimensions(pix_vec* retn);
32 |
33 | dmDataType get_data_type() { return m_dtype; }
34 | dmDescriptor* get_descriptor() { return m_descriptor; }
35 |
36 | private:
37 | descriptor(const descriptor& other); // disallow copy
38 | descriptor& operator=(const descriptor& other);
39 |
40 | private:
41 | dmDescriptor* m_descriptor;
42 | dmDataType m_dtype;
43 | };
44 |
45 | }
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/hideregions2/dm/dm.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_DM_HH
2 | #define DM_DM_HH
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/hideregions2/dm/exception.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_EXCEPTION_HH
2 | #define DM_EXCEPTION_HH
3 |
4 | #include
5 |
6 | namespace dm
7 | {
8 | class exception
9 | {
10 | public:
11 | exception() {}
12 | void set_descr(const std::string& t) { m_descr = t; }
13 | const std::string& operator() () { return m_descr; }
14 | private:
15 | std::string m_descr;
16 | };
17 |
18 | class except_unable_to_open : public exception {};
19 | class except_unable_to_create : public exception {};
20 | class except_invalid_param : public exception {};
21 | class except_copy_fail : public exception {};
22 | class except_block_create_fail : public exception {};
23 |
24 | class except_unknown : public exception {};
25 | }
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/hideregions2/dm/general.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "general.hh"
4 |
5 | dm::strlike::strlike(const std::string& str)
6 | {
7 | m_cpy = new char[str.size() + 1];
8 | std::strcpy( m_cpy, str.c_str());
9 | }
10 |
11 | dm::arraycopy::arraycopy(const pix_vec& array)
12 | {
13 | const unsigned no = array.size();
14 | m_copy = new long[no];
15 | for(unsigned i=0; i
5 | #include
6 |
7 | namespace dm
8 | {
9 | // method to use when opening file
10 | // create won't overwrite new files, create_over will
11 | enum open_mode { open, openrw, create, create_over };
12 |
13 | typedef std::vector pix_vec;
14 |
15 | // little class to make copies of strings
16 | // acts like a kind of 'smart-pointer'
17 | // needed because DM routines use char* rather than const char*
18 | class strlike
19 | {
20 | public:
21 | strlike(const std::string& str);
22 | ~strlike() { delete[] m_cpy; }
23 | char* operator() () { return m_cpy; }
24 | private:
25 | char* m_cpy;
26 | };
27 |
28 | // arraycopy
29 | // class to make a copy of a vector or unsigned* array
30 | class arraycopy
31 | {
32 | public:
33 | arraycopy(const pix_vec& array);
34 | arraycopy(unsigned no, const unsigned* list);
35 | ~arraycopy() { delete[] m_copy; }
36 |
37 | long* operator() () { return m_copy; }
38 | private:
39 | long* m_copy;
40 | };
41 |
42 | std::string to_str(int i);
43 | }
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/hideregions2/dm/image.cc:
--------------------------------------------------------------------------------
1 | #include "exception.hh"
2 | #include "image.hh"
3 |
4 | dm::image::image(dmBlock *init)
5 | : block(init),
6 | descriptor( dmImageGetDataDescriptor( m_block ) )
7 | {
8 | }
9 |
10 | dm::image::~image()
11 | {
12 | if( m_block != 0 )
13 | dmBlockClose(m_block);
14 |
15 | // don't do anything with descriptors (I think)
16 | }
17 |
18 | template void dm::image::create_memimage(memimage **im)
19 | {
20 | pix_vec dims;
21 | get_dimensions( &dims );
22 |
23 | if( dims.size() != 2 ) {
24 | except_invalid_param e;
25 | e.set_descr("Invalid number of dimensions in dm::image::create_memimage");
26 | throw e;
27 | }
28 |
29 | // lower range of coords
30 | pix_vec lower;
31 | lower.push_back(1); lower.push_back(1);
32 |
33 | // get data for range
34 | T* data;
35 | get_subarray(lower, dims, &data);
36 |
37 | // create image
38 | *im = new memimage(dims[0], dims[1], data);
39 |
40 | delete[] data;
41 | }
42 |
43 | template void dm::image::write_from_memimage(const memimage& im)
44 | {
45 | pix_vec dims;
46 | get_dimensions( &dims );
47 |
48 | if( dims.size() != 2 ) {
49 | except_invalid_param e;
50 | e.set_descr("Invalid number of dimensions in dm::image::write_from_memimage");
51 | throw e;
52 | }
53 |
54 | if( dims[0] != im.xw() || dims[1] != im.yw() ) {
55 | except_invalid_param e;
56 | e.set_descr("Dimensions of image and data block not matched");
57 | throw e;
58 | }
59 |
60 | // lower range of coords
61 | pix_vec lower;
62 | lower.push_back(1); lower.push_back(1);
63 |
64 | // copy data
65 | const std::valarray& data = im.data();
66 | const int size = data.size();
67 | T* copy = new T[size];
68 | for(int i=0; i **im); \
79 | template void \
80 | dm::image::write_from_memimage(const memimage& im);
81 |
82 | DM_DEFINE_TEMPL(short)
83 | DM_DEFINE_TEMPL(long)
84 | DM_DEFINE_TEMPL(float)
85 | DM_DEFINE_TEMPL(double)
86 | DM_DEFINE_TEMPL(unsigned char)
87 | DM_DEFINE_TEMPL(unsigned short)
88 | DM_DEFINE_TEMPL(unsigned long)
89 |
90 | #undef DM_DEFINE_TEMPL
91 |
--------------------------------------------------------------------------------
/hideregions2/dm/image.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_IMAGE_HH
2 | #define DM_IMAGE_HH
3 |
4 | #include "block.hh"
5 | #include "descriptor.hh"
6 | #include "memimage.hh"
7 |
8 | namespace dm
9 | {
10 | class image : public block, public descriptor
11 | {
12 | public:
13 | virtual ~image();
14 |
15 | // create an in-memory image from the file
16 | template void create_memimage(memimage **im);
17 | // write memory image to disk (note - must be same size!)
18 | template void write_from_memimage(const memimage& im);
19 |
20 | protected:
21 | image(dmBlock *init); // protected constructor
22 |
23 | friend class dataset;
24 |
25 | private:
26 | image(const image& other); // disallow copy usage
27 | image& operator=(const image& other); // disallow =
28 |
29 | private:
30 | dmDescriptor* m_descriptor;
31 | };
32 |
33 |
34 | }
35 |
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/hideregions2/dm/memimage.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "memimage.hh"
4 |
5 | template dm::memimage::memimage(const std::string& filename)
6 | {
7 | std::ifstream file(filename.c_str());
8 |
9 | file >> m_xw >> m_yw;
10 |
11 | m_data.resize(m_xw*m_yw);
12 | if( file )
13 | {
14 | for(unsigned y=0; y> operator()(x, y);
18 | }
19 | }
20 |
21 | if( ! file )
22 | {
23 | std::cerr << "Error reading from file\n";
24 | std::exit(1);
25 | }
26 |
27 | }
28 |
29 | template void dm::memimage::dump_to_file
30 | (const std::string& filename) const
31 | {
32 | std::ofstream file(filename.c_str());
33 |
34 | file << xw() << ' ' << yw() << '\n';
35 | for(unsigned y=0; y T& dm::memimage::pixel(unsigned x, unsigned y)
47 | {
48 | if( x >= m_xw || y >= m_yw)
49 | throw out_of_range_exception();
50 | return operator() (x, y);
51 | }
52 |
53 | // checked const pixel access
54 | template T dm::memimage::pixel(unsigned x, unsigned y) const
55 | {
56 | if( x >= m_xw || y >= m_yw)
57 | throw out_of_range_exception();
58 |
59 | return operator() (x, y);
60 | }
61 |
62 | #define DM_DEFINE_TEMPL(TYPE) \
63 | template class dm::memimage;
64 |
65 | DM_DEFINE_TEMPL(short)
66 | DM_DEFINE_TEMPL(long)
67 | DM_DEFINE_TEMPL(float)
68 | DM_DEFINE_TEMPL(double)
69 | DM_DEFINE_TEMPL(unsigned char)
70 | DM_DEFINE_TEMPL(unsigned short)
71 | DM_DEFINE_TEMPL(unsigned long)
72 |
73 | #undef DM_DEFINE_TEMPL
74 |
--------------------------------------------------------------------------------
/hideregions2/dm/memimage.hh:
--------------------------------------------------------------------------------
1 | #ifndef DM_MEMIMAGE_HH
2 | #define DM_MEMIMAGE_HH
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace dm {
10 |
11 | template class memimage
12 | {
13 | public:
14 | // blank image
15 | memimage(const unsigned xw, const unsigned yw, const T val = 0)
16 | : m_xw(xw), m_yw(yw), m_data( val, xw*yw )
17 | {}
18 |
19 | // copy image from another
20 | memimage(const memimage& other)
21 | : m_xw( other.m_xw ), m_yw( other.m_yw ), m_data( other.m_data )
22 | {}
23 |
24 | // initialise from C-style array
25 | memimage(const unsigned xw, const unsigned yw, const T* data)
26 | : m_xw( xw ), m_yw( yw ), m_data( data, xw*yw )
27 | {}
28 |
29 | // initialise from other datatypes
30 | template explicit memimage(const memimage& other);
31 | template memimage(const unsigned xw,
32 | const unsigned yw, const T2* const data);
33 |
34 | // read from dumpdata file
35 | memimage(const std::string& filename);
36 | // dump to file
37 | void dump_to_file(const std::string &filename) const;
38 |
39 | // set all the pixels
40 | void set_all(const T val = 0) { m_data = val; }
41 |
42 | // get access to pixels
43 | T& operator() (const unsigned x, const unsigned y)
44 | { return m_data[x+y*m_xw]; }
45 | T operator() (const unsigned x, const unsigned y) const
46 | { return m_data[x+y*m_xw]; }
47 |
48 | // get flat access to pixels
49 | T& flatdata(const unsigned i)
50 | { return m_data[i]; }
51 | T flatdata(const unsigned i) const
52 | { return m_data[i]; }
53 |
54 | // checked access to pixels
55 | class out_of_range_exception {};
56 | T& pixel(const unsigned x, const unsigned y);
57 | T pixel(const unsigned x, const unsigned y) const;
58 |
59 | class size_mismatch_exception {};
60 |
61 | // get maximum value in image
62 | T max() const
63 | {
64 | // get minimum value (not smallest value)
65 | T maxval = std::numeric_limits::is_integer
66 | ? std::numeric_limits::min()
67 | : -std::numeric_limits::max();
68 |
69 | const size_t len = m_xw*m_yw;
70 | for( size_t i = 0; i != len; ++i )
71 | maxval = std::max( maxval, m_data[i] );
72 | return maxval;
73 | }
74 |
75 | // get minimum value of image
76 | T min() const
77 | {
78 | T minval = std::numeric_limits::max();
79 |
80 | const size_t len = m_xw*m_yw;
81 | for( size_t i = 0; i != len; ++i )
82 | minval = std::min( minval, m_data[i] );
83 | return minval;
84 | }
85 |
86 | T sum() const
87 | {
88 | T tot = 0;
89 | const size_t len = m_xw*m_yw;
90 | for( size_t i = 0; i != len; ++i )
91 | tot += m_data[i];
92 | return tot;
93 | }
94 |
95 | // make all values <= upperval
96 | void trim_down(const T upperval)
97 | {
98 | const size_t len = m_xw*m_yw;
99 | for( size_t i = 0; i != len; ++i )
100 | m_data[i] = std::min( m_data[i], upperval );
101 | }
102 |
103 | // make all values >= lowerval
104 | void trim_up(const T lowerval)
105 | {
106 | const size_t len = m_xw*m_yw;
107 | for( size_t i = 0; i != len; ++i )
108 | m_data[i] = std::max( m_data[i], lowerval );
109 | }
110 |
111 | private:
112 | void assert_size_other(const memimage& other) const
113 | {
114 | if( m_xw != other.xw() || m_yw != other.yw() )
115 | throw size_mismatch_exception();
116 | }
117 |
118 | public:
119 | // various operations with images
120 | // multiply image by another
121 | const memimage& operator *= (const memimage& other)
122 | {
123 | assert_size_other(other); m_data *= other.data(); return *this;
124 | }
125 | const memimage& operator /= (const memimage& other)
126 | {
127 | assert_size_other(other); m_data /= other.data(); return *this;
128 | }
129 | const memimage& operator -= (const memimage& other)
130 | {
131 | assert_size_other(other); m_data -= other.data(); return *this;
132 | }
133 | const memimage& operator += (const memimage& other)
134 | {
135 | assert_size_other(other); m_data += other.data(); return *this;
136 | }
137 |
138 | // with constants
139 | const memimage& operator *= (const T other)
140 | {
141 | m_data *= other; return *this;
142 | }
143 | const memimage& operator /= (const T other)
144 | {
145 | m_data /= other; return *this;
146 | }
147 | const memimage& operator -= (const T other)
148 | {
149 | m_data -= other; return *this;
150 | }
151 | const memimage& operator += (const T other)
152 | {
153 | m_data += other; return *this;
154 | }
155 |
156 | // return information about the image
157 | unsigned xw() const { return m_xw; } // return width
158 | unsigned yw() const { return m_yw; } // return height
159 | unsigned nelem() const { return m_xw*m_yw; } // no elements
160 | const std::valarray& data() const { return m_data; } // return data
161 |
162 | // these make temporaries
163 | memimage operator * (const memimage& other) const
164 | {
165 | memimage t = *this; t *= other; return t;
166 | }
167 | memimage operator / (const memimage& other) const
168 | {
169 | memimage t = *this; t /= other; return t;
170 | }
171 | memimage operator - (const memimage& other) const
172 | {
173 | memimage t = *this; t -= other; return t;
174 | }
175 | memimage operator + (const memimage& other) const
176 | {
177 | memimage t = *this; t += other; return t;
178 | }
179 |
180 | // with constants
181 | memimage operator * (const T other) const
182 | {
183 | memimage t = *this; t *= other; return t;
184 | }
185 | memimage operator / (const T other) const
186 | {
187 | memimage t = *this; t /= other; return t;
188 | }
189 | memimage operator + (const T other) const
190 | {
191 | memimage t = *this; t += other; return t;
192 | }
193 | memimage operator - (const T other) const
194 | {
195 | memimage t = *this; t -= other; return t;
196 | }
197 |
198 | private:
199 | unsigned m_xw, m_yw;
200 | std::valarray m_data;
201 | };
202 |
203 |
204 | } // namespace
205 |
206 | // convert types
207 | // put this in the header, as we'd generate 10^6 versions of this
208 | // otherwise.
209 | template template
210 | dm::memimage::memimage(const unsigned xw, const unsigned yw,
211 | const T2* const data)
212 | : m_xw(xw), m_yw(yw),
213 | m_data( data, nelem() )
214 | {
215 | const unsigned size = nelem();
216 | for(unsigned i=0; i != size; ++i)
217 | m_data[i] = static_cast( data[i] );
218 | }
219 |
220 | // copy image of different type
221 | template template
222 | dm::memimage::memimage(const memimage& other)
223 | : m_xw( other.xw() ), m_yw( other.yw() ),
224 | m_data( static_cast(0), nelem() )
225 | {
226 | const unsigned size = nelem();
227 | const std::valarray& otherdata = other.data();
228 |
229 | for(unsigned i=0; i != size; ++i)
230 | m_data[i] = static_cast(otherdata[i]);
231 | }
232 |
233 | #endif
234 |
--------------------------------------------------------------------------------
/hideregions2/dm/test.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "dataset.hh"
6 | #include "image.hh"
7 | #include "exception.hh"
8 | #include "general.hh"
9 | #include "memimage.hh"
10 |
11 | int main()
12 | {
13 | try {
14 | dm::dataset ds("cen_image_b2.fits", dm::open);
15 |
16 | dm::image* im = ds.get_image();
17 |
18 | dm::memimage* mem;
19 | im->create_memimage(&mem);
20 | dm::memimage& m = *mem;
21 |
22 | std::cout << m(19, 19) << '\n';
23 |
24 | delete mem;
25 | delete im;
26 | }
27 | catch( dm::exception& e ) {
28 | std::cout << "Exception: "
29 | << e() << '\n';
30 | }
31 |
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/hideregions2/hideregions2.cc:
--------------------------------------------------------------------------------
1 | // New version of hide regions, which iterates over input regions,
2 | // replacing contents of regions with random choices from the pixels
3 | // in a slightly expanded region
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #define EXPANDSIZE 1
18 |
19 | // standard CAIO region files header
20 | extern "C"
21 | {
22 | # include
23 | }
24 |
25 | class Region
26 | {
27 | public:
28 | Region(const std::string& str)
29 | {
30 | reg = regParse(const_cast(str.c_str()));
31 | if(reg == 0)
32 | throw std::string("Invalid region: ") + str;
33 | }
34 |
35 | ~Region()
36 | {
37 | regFree(reg);
38 | }
39 |
40 | bool inside(double x, double y)
41 | {
42 | return regInsideRegion(reg, x, y);
43 | }
44 |
45 | private:
46 | regRegion* reg;
47 | };
48 |
49 | struct Transform
50 | {
51 | Transform(dm::image* im)
52 | {
53 | dmDescriptor* imdesc = im->get_descriptor();
54 | dmDescriptor* phys = dmArrayGetAxisGroup(imdesc, 1);
55 | dmCoordGetTransform_d(phys, pcrpix, pcrval, pcdlt, 2);
56 | }
57 |
58 | double x2phys(unsigned x) const
59 | {
60 | return (x + 1 - pcrpix[0])*pcdlt[0] + pcrval[0];
61 | }
62 |
63 | double y2phys(unsigned y) const
64 | {
65 | return (y + 1 - pcrpix[1])*pcdlt[1] + pcrval[1];
66 | }
67 |
68 | double pcrpix[2], pcrval[2], pcdlt[2];
69 | };
70 |
71 | void fillRegion(Region* reg, Region* enlarge, const Transform& trans,
72 | const dm::memimage* inimage,
73 | dm::memimage* outimage)
74 | {
75 | std::vector vals;
76 |
77 | unsigned minx=outimage->xw(), maxx=0;
78 | unsigned miny=outimage->yw(), maxy=0;
79 |
80 | for(unsigned y = 0; y < inimage->yw(); ++y)
81 | for(unsigned x = 0; x < inimage->xw(); ++x)
82 | {
83 | double px = trans.x2phys(x);
84 | double py = trans.y2phys(y);
85 |
86 | if(enlarge->inside(px, py) && !reg->inside(px, py))
87 | {
88 | minx=std::min(minx, x);
89 | miny=std::min(miny, y);
90 | maxx=std::max(maxx, x);
91 | maxy=std::max(maxy, y);
92 |
93 | vals.push_back((*inimage)(x, y));
94 | }
95 | }
96 |
97 | if(vals.empty())
98 | return;
99 |
100 | for(unsigned y = miny; y <= maxy; ++y)
101 | for(unsigned x = minx; x <= maxx; ++x)
102 | {
103 | double px = trans.x2phys(x);
104 | double py = trans.y2phys(y);
105 |
106 | if(reg->inside(px, py))
107 | {
108 | (*outimage)(x, y) =
109 | vals[unsigned(rand()*(1./RAND_MAX)*vals.size())];
110 | }
111 | }
112 | }
113 |
114 | std::string enlargeRegion(const std::string& str)
115 | {
116 | boost::char_separator sep("(,)");
117 | boost::tokenizer< boost::char_separator > tokens(str, sep);
118 | //BOOST_FOREACH (const std::string& t, tokens) {
119 | // std::cout << t << "." << std::endl;
120 | // }
121 |
122 | boost::tokenizer< boost::char_separator >::iterator it = tokens.begin();
123 |
124 | std::string name(*it++);
125 | std::string out(name + "(");
126 | if(name == "ellipse")
127 | {
128 | out += *it++;
129 | out += ",";
130 | out += *it++;
131 | out += ",";
132 |
133 | double rad1(boost::lexical_cast(*it++));
134 | out += boost::lexical_cast(rad1+EXPANDSIZE);
135 | out += ",";
136 | double rad2(boost::lexical_cast(*it++));
137 | out += boost::lexical_cast(rad2+EXPANDSIZE);
138 | out += ",";
139 |
140 | out += *it++;
141 | }
142 | else if(name == "circle")
143 | {
144 | out += *it++;
145 | out += ",";
146 | out += *it++;
147 | out += ",";
148 |
149 | double rad(boost::lexical_cast(*it++));
150 | out += boost::lexical_cast(rad+EXPANDSIZE);
151 | }
152 | else
153 | {
154 | throw std::string("Cannot interpret region");
155 | }
156 |
157 | out += ")";
158 | return out;
159 | }
160 |
161 | void run(const std::string& infile,
162 | const std::string& regfile,
163 | const std::string& outfile)
164 | {
165 | // load in image
166 | dm::dataset ds(infile);
167 | dm::image* im = ds.get_image();
168 |
169 | Transform trans(im);
170 |
171 | // load the input image into memory
172 | dm::memimage* inimage;
173 | im->create_memimage(&inimage);
174 |
175 | dm::memimage outimage(inimage->xw(), inimage->yw());
176 | for(unsigned y=0; y= 1 && line[0] == '#')
190 | continue;
191 |
192 | std::cout << "Region: " << line << '\n';
193 | Region reg(line);
194 |
195 | Region enlarge( enlargeRegion(line) );
196 |
197 | fillRegion(®, &enlarge, trans, inimage, &outimage);
198 | }
199 |
200 | dm::dataset ds_im_out(outfile, dm::create_over);
201 | dm::image *im_im_out = ds_im_out.create_image("IMAGE", dmFLOAT,
202 | outimage.xw(),
203 | outimage.yw());
204 | im_im_out->write_from_memimage(outimage);
205 | }
206 |
207 | int main(int argc, char* argv[])
208 | {
209 | if( argc != 4 )
210 | {
211 | std::cerr << "Usage: "
212 | << argv[0]
213 | << " infile.fits region.reg outfile.fits\n";
214 | return 1;
215 | }
216 |
217 | try
218 | {
219 | run(argv[1], argv[2], argv[3]);
220 | }
221 | catch(std::string s)
222 | {
223 | std::cerr << s << '\n';
224 | return 1;
225 | }
226 |
227 | return 0;
228 | }
229 |
--------------------------------------------------------------------------------