mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
milkImage.hpp
Go to the documentation of this file.
1/** \file milkImage.hpp
2 * \brief Interface to MILK::ImageStreamIO shared memory streams
3 * \ingroup image_processing_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef improc_milkImage_hpp
28#define improc_milkImage_hpp
29
30#ifdef MXLIB_MILK
31
32#ifdef MXLIB_CUDA
33#define HAVE_CUDA
34#endif
35
36#include <ImageStreamIO/ImageStreamIO.h>
37
38#include "../mxException.hpp"
39#include "eigenImage.hpp"
40
41namespace mx
42{
43namespace improc
44{
45
46template <typename typeT>
47struct ImageStructTypeCode;
48
49template <>
50struct ImageStructTypeCode<uint8_t>
51{
52 constexpr static int TypeCode = _DATATYPE_UINT8;
53};
54
55template <>
56struct ImageStructTypeCode<int8_t>
57{
58 constexpr static int TypeCode = _DATATYPE_INT8;
59};
60
61template <>
62struct ImageStructTypeCode<char>
63{
64 constexpr static int TypeCode = _DATATYPE_INT8;
65};
66
67template <>
68struct ImageStructTypeCode<uint16_t>
69{
70 constexpr static int TypeCode = _DATATYPE_UINT16;
71};
72
73template <>
74struct ImageStructTypeCode<int16_t>
75{
76 constexpr static int TypeCode = _DATATYPE_INT16;
77};
78
79template <>
80struct ImageStructTypeCode<uint32_t>
81{
82 constexpr static int TypeCode = _DATATYPE_UINT32;
83};
84
85template <>
86struct ImageStructTypeCode<int32_t>
87{
88 constexpr static int TypeCode = _DATATYPE_INT32;
89};
90
91template <>
92struct ImageStructTypeCode<uint64_t>
93{
94 constexpr static int TypeCode = _DATATYPE_UINT64;
95};
96template <>
97struct ImageStructTypeCode<int64_t>
98{
99 constexpr static int TypeCode = _DATATYPE_INT64;
100};
101template <>
102struct ImageStructTypeCode<float>
103{
104 constexpr static int TypeCode = _DATATYPE_FLOAT;
105};
106
107template <>
108struct ImageStructTypeCode<double>
109{
110 constexpr static int TypeCode = _DATATYPE_DOUBLE;
111};
112
113template <>
114struct ImageStructTypeCode<std::complex<float>>
115{
116 constexpr static int TypeCode = _DATATYPE_COMPLEX_FLOAT;
117};
118
119template <>
120struct ImageStructTypeCode<std::complex<double>>
121{
122 constexpr static int TypeCode = _DATATYPE_COMPLEX_DOUBLE;
123};
124
125/// Class to interface with an ImageStreamIO image in shared memory
126/**
127 *
128 * Use with Eigen::Map (aliased as mx::improc::eigenMap)
129 * \code
130 * using namespace mx::improc;
131 * milkImage<float> mim("image"); //connects to image.im.shm
132 * eigenMap<float> im(mim); //the conversion operator passes a reference to the internal map
133 * im.setRandom(); // im is now a map pointed at the image data. Eigen functions are now available.
134 * im(64,64) *= 2000;
135 * im /= 0.2;
136 * \endcode
137 * Once you have changed something via the Eigen::Map you want to notify others connected to the stream
138 * via
139 * \code
140 * mim.post();
141 * \endcode
142 *
143 * \ingroup eigen_image_processing
144 */
145template <typename _dataT>
146class milkImage
147{
148 public:
149 typedef _dataT dataT; ///< The data type
150
151 protected:
152 std::string m_name; ///< The image name, from name.im.shm (the .im.shm should not be given).
153
154 IMAGE *m_image{ nullptr }; ///< Pointer to the ImageStreamIO IMAGE structure.
155
156 dataT *m_raw{ nullptr }; // The raw pointer address is stored here for checks
157
158 eigenMap<dataT> *m_map{ nullptr }; // An Eigen::Map of the array
159
160 uint64_t m_size_0{ 0 }; ///< The size[0] of the image when last opened.
161
162 uint64_t m_size_1{ 0 }; ///< The size[1] of the image when last opened.
163
164 bool m_passive {false}; /**< If true then the cnt0 counter is not incremented on post. Usage: this will not
165 trigger the dmcomb process in cacao, so the DM will not pick up the shape until
166 something does trigger it. */
167
168 public:
169 /// Default c'tor
170 milkImage();
171
172 /// Constructor which opens the specified image, which must already exist in shared memory.
173 milkImage(
174 const std::string &imname /**< [in] The image name, from name.im.shm (the .im.shm should not be given).*/ );
175
176 /// Constructor which (re-)creates the specified image with the given size
177 milkImage( const std::string &imname, ///< [in] The image name, from name.im.shm (the .im.shm should not be given).
178 uint32_t sz0, ///< [in] the x size of the image
179 uint32_t sz1 ///< [in] the y size of the image
180 );
181
182 /// Constructor which (re-)creates the specified image and copies the provided image to it
183 milkImage( const std::string &imname, ///< [in] The image name, from name.im.shm (the .im.shm should not be given).
184 const eigenImage<dataT> &im ///< [in] An existing eigenImage
185 );
186
187 /// D'tor
188 ~milkImage();
189
190 /// Open and connect to an image, allocating the eigenMap.
191 /**
192 * \throws std::invalid_argument if the image type_code does not match dataT.
193 */
194 void
195 open( const std::string &imname /**< [in] The image name, from name.im.shm (the .im.shm should not be given).*/ );
196
197 /// Create (or re-create) and connect to an image, allocating the eigenMap.
198 /**
199 * \throws std::invalid_argument if the image type_code does not match dataT.
200 */
201 void create( const std::string &imname, ///< [in] The image name, for name.im.shm (the .im.shm should not be given).
202 uint32_t sz0, ///< [in] the x size of the image
203 uint32_t sz1 ///< [in] the y size of the image
204 );
205
206 /// Create and connect to an image using an existing eigenImage, allocating the eigenMap and copying the image to
207 /// the shmim.
208 /**
209 * \throws std::invalid_argument if the image type_code does not match dataT.
210 */
211 void create( const std::string &imname, ///< [in] The image name, for name.im.shm (the .im.shm should not be given).
212 const eigenImage<dataT> &im ///< [in] An existing eigenImage
213 );
214
215 /// Get the width of the image
216 /**
217 * \returns the current value of m_size_0
218 */
219 uint32_t rows();
220
221 /// Get the height of the image
222 /**
223 * \returns the current value of m_size_1
224 */
225 uint32_t cols();
226
227 /// Get the size of a dimension of the image
228 /**
229 * \returns the current value of m_size_0 or m_size_1 depending on n
230 */
231 uint32_t size( unsigned n /**< [in] the dimension to get the size of*/ );
232
233 /// Set the passive flag
234 /** Sets \ref m_passive
235 *
236 */
237 void passive( bool pass /**< [in] new value of the \ref m_passive flag */);
238
239 /// Get the passive flag
240 /** Gets \ref m_passive
241 *
242 */
243 bool passive();
244
245 /// Checks if the image is connected and is still the same format as when connected.
246 /** Checks on pointer value, size[], and data_type.
247 *
248 * \todo check inode!
249 *
250 * \returns true if connected and no changes
251 * \returns false if not connected or something changed. All maps are now invalid.
252 */
253 bool valid();
254
255 /// Reopens the image.
256 /** Same as
257 * \code
258 * close();
259 * open(m_name);
260 * \endcode
261 */
262 void reopen();
263
264 // Close the image
265 void close();
266
267 /// Get an eigenMap
268 /** Use with caution:
269 * - there is no way to know if the image has changed
270 * - you should check \ref valid() before using
271 *
272 *
273 * \returns an Eigen::Map<Array,-1,-1> reference
274 *
275 * \throws mx::err::mxException if the image is not opened
276 *
277 */
278 eigenMap<dataT> &operator()();
279
280 /// Conversion operator returns an eigenMap
281 /** Use this like
282 * \code
283 * milkImage<float> mim("imname");
284 * eigenMap<float> im(mim); //you now have an Eigen interface to the image
285 * \endcode
286 * but with caution:
287 * - there is no way to know if the image has changed
288 * - you should check \ref valid() before using
289 *
290 *
291 * \returns an Eigen::Map<Array,-1,-1> object
292 *
293 * \throws mx::err::mxException if the image is not opened
294 *
295 */
296 operator eigenMap<dataT>();
297
298 /// Copy data from an Eigen Array type to the shared memory stream
299 /** Sets the write flag, copies using the Eigen assigment to map, unsets the write flag, then posts.
300 *
301 * \throws mxException on an error
302 *
303 */
304 template <typename eigenT>
305 milkImage &operator=( const eigenT &im /**< [in] the eigen array to copy to the stream*/ );
306
307 /// Set the write flag
308 /** The write flag is set to indicate whether or not the the data is being changed.
309 * The write flag will be set to false by \ref post().
310 *
311 * \throws mx::err::mxException if the image is not opened
312 */
313 void setWrite( bool wrflag = true /**< [in] [optional] the desired value of the write flag. Default is true.*/ );
314
315 /// Update the metadata and post all semaphores
316 /**
317 * \todo need to set wtime, have a version with atime
318 *
319 * \throws mx::err::mxException if the image is not opened
320 */
321 void post();
322};
323
324template <typename dataT>
325milkImage<dataT>::milkImage()
326{
327}
328
329template <typename dataT>
330milkImage<dataT>::milkImage( const std::string &imname )
331{
332 open( imname );
333}
334
335template <typename dataT>
336milkImage<dataT>::milkImage( const std::string &imname, const eigenImage<dataT> &im )
337{
338 create( imname, im );
339}
340
341template <typename dataT>
342milkImage<dataT>::milkImage( const std::string &imname, uint32_t sz0, uint32_t sz1 )
343{
344 create( imname, sz0, sz1 );
345}
346
347template <typename dataT>
348milkImage<dataT>::~milkImage()
349{
350 close();
351}
352
353template <typename dataT>
354void milkImage<dataT>::open( const std::string &imname )
355{
356 if( m_image )
357 {
358 ImageStreamIO_closeIm( m_image );
359 delete m_image;
360 m_image = nullptr;
361 }
362
363 if( m_map )
364 {
365 delete m_map;
366 m_map = nullptr;
367 }
368
369 m_image = new IMAGE;
370
371 errno_t rv = ImageStreamIO_openIm( m_image, imname.c_str() );
372
373 if( rv != IMAGESTREAMIO_SUCCESS )
374 {
375 delete m_image;
376 m_image = nullptr;
377 throw err::mxException( "", 0, "", 0, "", 0, "ImageStreamIO_openIm returned an error" );
378 }
379
380 if( ImageStructTypeCode<dataT>::TypeCode != m_image->md->datatype )
381 {
382 delete m_image;
383 m_image = nullptr;
384 throw std::invalid_argument( "shmim datatype does not match template type" );
385 }
386
387 m_name = imname;
388 m_raw = (dataT *)m_image->array.raw;
389 m_size_0 = m_image->md->size[0];
390 m_size_1 = m_image->md->size[1];
391
392 m_map = new eigenMap<dataT>( m_raw, m_size_0, m_size_1 );
393}
394
395template <typename dataT>
396void milkImage<dataT>::create( const std::string &imname, uint32_t sz0, uint32_t sz1 )
397{
398 if( m_image )
399 {
400 ImageStreamIO_closeIm( m_image );
401 delete m_image;
402 m_image = nullptr;
403 }
404
405 if( m_map )
406 {
407 delete m_map;
408 m_map = nullptr;
409 }
410
411 m_image = new IMAGE;
412
413 uint32_t imsize[3];
414 imsize[0] = sz0;
415 imsize[1] = sz1;
416 imsize[2] = 1;
417
418 errno_t rv = ImageStreamIO_createIm_gpu( m_image,
419 imname.c_str(),
420 3,
421 imsize,
422 ImageStructTypeCode<dataT>::TypeCode,
423 -1,
424 1,
425 IMAGE_NB_SEMAPHORE,
426 0,
427 CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
428 0 );
429
430 if( rv != IMAGESTREAMIO_SUCCESS )
431 {
432 delete m_image;
433 m_image = nullptr;
434 throw err::mxException( "", 0, "", 0, "", 0, "ImageStreamIO_createIm_gpu returned an error" );
435 }
436
437 if( ImageStructTypeCode<dataT>::TypeCode != m_image->md->datatype )
438 {
439 delete m_image;
440 m_image = nullptr;
441 throw std::invalid_argument( "shmim datatype does not match template type" );
442 }
443
444 m_name = imname;
445 m_raw = (dataT *)m_image->array.raw;
446 m_size_0 = m_image->md->size[0];
447 m_size_1 = m_image->md->size[1];
448
449 m_map = new eigenMap<dataT>( m_raw, m_size_0, m_size_1 );
450}
451
452template <typename dataT>
453void milkImage<dataT>::create( const std::string &imname, const eigenImage<dataT> &im )
454{
455 create( imname, im.rows(), im.cols() );
456 operator=( im );
457}
458
459template <typename dataT>
460eigenMap<dataT> &milkImage<dataT>::operator()()
461{
462 if( m_map == nullptr )
463 {
464 throw err::mxException( "", 0, "", 0, "", 0, "Image is not open (map is null)" );
465 }
466
467 return *m_map;
468}
469
470template <typename dataT>
471milkImage<dataT>::operator eigenMap<dataT>()
472{
473 return operator()();
474}
475
476template <typename dataT>
477void milkImage<dataT>::reopen()
478{
479 close();
480 open( m_name );
481}
482
483template <typename dataT>
484void milkImage<dataT>::close()
485{
486 if( m_map != nullptr )
487 {
488 delete m_map;
489 m_map = nullptr;
490 }
491
492 if( m_image == nullptr )
493 {
494 return;
495 }
496
497 errno_t rv = ImageStreamIO_closeIm( m_image );
498 delete m_image;
499 m_image = nullptr;
500
501 if( rv != IMAGESTREAMIO_SUCCESS )
502 throw err::mxException( "", 0, "", 0, "", 0, "ImageStreamIO_closeIm returned an error" );
503}
504
505template <typename dataT>
506uint32_t milkImage<dataT>::rows()
507{
508 return m_size_0;
509}
510
511template <typename dataT>
512uint32_t milkImage<dataT>::cols()
513{
514 return m_size_1;
515}
516
517template <typename dataT>
518uint32_t milkImage<dataT>::size( unsigned n )
519{
520 if( n == 0 )
521 {
522 return m_size_0;
523 }
524 else if( n == 1 )
525 {
526 return m_size_1;
527 }
528
529 return 0;
530}
531
532template <typename dataT>
533void milkImage<dataT>::passive(bool pass)
534{
535 m_passive = pass;
536}
537
538template <typename dataT>
539bool milkImage<dataT>::passive()
540{
541 return m_passive;
542}
543
544template <typename dataT>
545bool milkImage<dataT>::valid()
546{
547 if( m_image == nullptr )
548 {
549 return false;
550 }
551
552 if( m_raw != (dataT *)m_image->array.raw || m_size_0 != m_image->md->size[0] || m_size_1 != m_image->md->size[1] ||
553 ImageStructTypeCode<dataT>::TypeCode != m_image->md->datatype )
554 {
555 return false;
556 }
557
558 return true;
559}
560
561template <typename dataT>
562template <typename eigenT>
563milkImage<dataT> &milkImage<dataT>::operator=( const eigenT &im )
564{
565 if( m_image == nullptr )
566 {
567 throw err::mxException( "", 0, "", 0, "", 0, "Image is not open (image is null)" );
568 }
569
570 if( m_map == nullptr )
571 {
572 throw err::mxException( "", 0, "", 0, "", 0, "Image is not open (map is null)" );
573 }
574
575 setWrite( true );
576
577 *m_map = im;
578
579 setWrite( false );
580
581 post();
582
583 return *this;
584}
585
586template <typename dataT>
587void milkImage<dataT>::setWrite( bool wrflag )
588{
589 if( m_image == nullptr )
590 {
591 throw err::mxException( "", 0, "", 0, "", 0, "Image is not open" );
592 }
593
594 m_image->md->write = wrflag;
595}
596
597template <typename dataT>
598void milkImage<dataT>::post()
599{
600 if( m_image == nullptr )
601 {
602 throw err::mxException( "", 0, "", 0, "", 0, "Image is not open" );
603 }
604
605 if(!m_passive)
606 {
607 errno_t rv = ImageStreamIO_UpdateIm( m_image );
608 m_image->md->atime = m_image->md->writetime;
609
610 if( rv != IMAGESTREAMIO_SUCCESS )
611 {
612 throw err::mxException( "", 0, "", 0, "", 0, "ImageStreamIO_UpdateIm returned an error" );
613 }
614 }
615 else
616 {
617 if(clock_gettime(CLOCK_ISIO, &m_image->md->writetime) == -1)
618 {
619 throw err::mxException( "", 0, "", 0, "", 0, "clock_gettime returned an error" );
620 }
621 m_image->md->atime = m_image->md->writetime;
622
623 m_image->md->write = 0;
624 ImageStreamIO_sempost( m_image, -1 );
625 }
626}
627
628} // namespace improc
629} // namespace mx
630
631#endif // MXLIB_MILK
632#endif // improc_milkImage_hpp
Tools for using the eigen library for image processing.
The mxlib c++ namespace.
Definition mxError.hpp:40