/******************************************************************************* * Copyright (c) 2021 Nerian Vision GmbH * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *******************************************************************************/ #ifndef VISIONTRANSFER_IMAGESET_H #define VISIONTRANSFER_IMAGESET_H #include #include #include "visiontransfer/common.h" namespace visiontransfer { /** * \brief A set of one to three images, but usually two (the left camera image * and the disparity map). One- and three-image modes can be enabled * in the device configuration interface. * * For backwards compatibility, for sets of at least two images the image at * index 0 is always the left camera image, while the one at index 1 is either the * disparity map if in disparity processing mode, or the right image otherwise. * * All images must be of equal width and height, but are allowed to have * different pixel formats. Please note that the class does not manage the * pixel data but only keeps pointers. You thus need to ensure that the pixel * data remains valid for as long as this object persists. */ class VT_EXPORT ImageSet { public: static const int MAX_SUPPORTED_IMAGES = 3; /** * \brief Image formats that can be transferred. */ enum ImageFormat { /// 8-bit greyscale format FORMAT_8_BIT_MONO, /// 8-bit RGB format FORMAT_8_BIT_RGB, /// 12-bit greyscale format plus 4 bits of padding /// (hence a total of 16 bits). FORMAT_12_BIT_MONO }; /** * \deprecated Please use the new format constants in \c ImageFormat. */ enum ImageFormat_Deprecated { FORMAT_8_BIT = FORMAT_8_BIT_MONO, FORMAT_12_BIT = FORMAT_12_BIT_MONO }; /** * \brief Supported image types */ enum ImageType { IMAGE_UNDEFINED, IMAGE_LEFT, IMAGE_DISPARITY, IMAGE_RIGHT, }; /** * \brief Default constructor creating an image set with no pixel data. */ ImageSet(); /** * \brief Copy constructor creating a shallow copy of the image set. */ ImageSet(const ImageSet& other); ~ImageSet(); ImageSet& operator= (ImageSet const& other); /** * \brief Sets a new width for both images. */ void setWidth(int w) {width = w;} /** * \brief Sets a new width for both images. */ void setHeight(int h) {height = h;} /** * \brief Sets a new row stride for the pixel data of one image. * * \param imageNumber Number of the image for which to set the * row stride (0 ... getNumberOfImages()-1). * \param stride The row stride that shall be set. */ void setRowStride(int imageNumber, int stride) { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); rowStride[imageNumber] = stride; } /** * \brief Sets the pixel format for the given image. * * \param imageNumber Number of the image for which to set the * pixel format (0 ... getNumberOfImages()-1). * \param format The pixel format that shall be set. */ void setPixelFormat(int imageNumber, ImageFormat format) { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); formats[imageNumber] = format; } #ifndef DOXYGEN_SHOULD_SKIP_THIS DEPRECATED("Use setPixelFormat(int, ImageFormat) instead") void setPixelFormat(int imageNumber, ImageFormat_Deprecated format) { setPixelFormat(imageNumber, static_cast(format)); } #endif /** * \brief Sets the pixel data for the given image. * * \param imageNumber Number of the image for which to set the * pixel data (0 ... getNumberOfImages()-1). * \param pixelData The pixel data that shall be set. */ void setPixelData(int imageNumber, unsigned char* pixelData) { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); data[imageNumber] = pixelData; } /** * \brief Sets the pointer to the disparity-to-depth mapping matrix q. * * No data is copied. The data which q is pointing to has to remain valid * for as long as this object exists. */ void setQMatrix(const float* q) { qMatrix = q; } /** * \brief Sets the sequence number for this image set. */ void setSequenceNumber(unsigned int num) { seqNum = num; } /** * \brief Sets the time at which this image set has been captured. * * \param seconds The time stamp with a resolution of one second. * \param microsec The fractional seconds part of the time stamp with * a resolution of 1 microsecond. */ void setTimestamp(int seconds, int microsec) { timeSec = seconds; timeMicrosec = microsec; } /** * \brief Sets the value range for the disparity map contained in this * image set. * * \param minimum Minimum disparity value. * \param maximum Maximum disparity value. */ void setDisparityRange(int minimum, int maximum) { minDisparity = minimum; maxDisparity = maximum; } /** * \brief Sets the subpixel factor for this image set. */ void setSubpixelFactor(int subpixFact) { subpixelFactor = subpixFact; } #ifndef DOXYGEN_SHOULD_SKIP_THIS /** * \brief Sets whether this is a left camera image and disparity * map set, or two raw camera images. * * DEPRECATION NOTICE: Please use setNumberOfImages() and setIndexOf() * for more comprehensive control of the images in the image set. */ DEPRECATED("Only compatible with two-image sets: use setNumberOfImages() and setIndexOf() instead") void setImageDisparityPair(bool dispPair); #endif /** * \brief Returns the width of each image. */ int getWidth() const {return width;} /** * \brief Returns the height of each image. */ int getHeight() const {return height;} /** * \brief Returns the row stride for the pixel data of one image. * * \param imageNumber Number of the image for which to obtain the * row stride (0 ... getNumberOfImages()-1). * * Please use getRowStride(ImageSet::ImageType) to access the * data by their abstract role in lieu of their index in the set. */ int getRowStride(int imageNumber) const { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); return rowStride[imageNumber]; } /** * \brief Returns the row stride for the pixel data of one image. * * \param what ImageType of the desired channel. * * This function will throw an exception when the ImageType * is not present in this set (use hasImageType(what) to check). */ int getRowStride(ImageType what) const { int idx = getIndexOf(what, true); return getRowStride(idx); } /** * \brief Returns the pixel format for the given image. * * \param imageNumber Number of the image for which to receive the * pixel format (0 ... getNumberOfImages()-1). * * Please use getPixelFormat(ImageSet::ImageType) to access the * data by their abstract role in lieu of their index in the set. */ ImageFormat getPixelFormat(int imageNumber) const { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); return formats[imageNumber]; } /** * \brief Returns the pixel format for the given image. * * \param what ImageType of the desired channel. * * This function will throw an exception when the ImageType * is not present in this set (use hasImageType(what) to check). */ ImageFormat getPixelFormat(ImageType what) const { int idx = getIndexOf(what, true); return getPixelFormat(idx); } /** * \brief Returns the pixel data for the given image. * * \param imageNumber Number of the image for which to receive the * pixel data (0 ... getNumberOfImages()-1). * * Please use getPixelData(ImageSet::ImageType) to access the * data by their abstract role in lieu of their index in the set. */ unsigned char* getPixelData(int imageNumber) const { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); return data[imageNumber]; } /** * \brief Returns the pixel data for the given image. * * \param what ImageType of the desired channel. * * This function will throw an exception when the ImageType * is not present in this set (use hasImageType(what) to check). */ unsigned char* getPixelData(ImageType what) const { int idx = getIndexOf(what, true); return getPixelData(idx); } /** * \brief Returns a pointer to the disparity-to-depth mapping matrix q. */ const float* getQMatrix() const { return qMatrix; } /** * \brief Returns the sequence number for this image set. */ unsigned int getSequenceNumber() const {return seqNum;} /** * \brief Returns the time at which this image set has been captured. * * \param seconds The time stamp with a resolution of one second. * \param microsec The fractional seconds part of the time stamp with * a resolution of 1 microsecond. */ void getTimestamp(int& seconds, int& microsec) const { seconds = timeSec; microsec = timeMicrosec; } /** * \brief Gets the value range for the disparity map contained in this * image set. If the image set does not contain any disparity data * then the disparity range is undefined. * * \param minimum Minimum disparity value. * \param maximum Maximum disparity value. */ void getDisparityRange(int& minimum, int& maximum) const { minimum = minDisparity; maximum = maxDisparity; } /** * \brief Gets the subpixel factor for this image set. */ int getSubpixelFactor() const { return subpixelFactor; } /** * \brief Writes one image of the set to a PGM or PPM file. * * \param imageNumber The number of the image that shall be written. * \param File name of the PGM or PPM file that shall be created. */ void writePgmFile(int imageNumber, const char* fileName) const; #ifndef DOXYGEN_SHOULD_SKIP_THIS /** * \brief Returns true if this is a left camera image and disparity * map pair. * * DEPRECATION NOTICE: this is a legacy function; in case of image sets * with one or three images, the result may not be as expected * (this functions returns true only for the case of exactly two images: * left image plus disparity image). * * The new function hasImageType(ImageSet::ImageType) provides better * granularity of what data are enabled and present. */ DEPRECATED("Only compatible with two-image sets: use hasImageType(ImageSet::IMAGE_DISPARITY) instead") bool isImageDisparityPair() const { return (getNumberOfImages()==2) && hasImageType(IMAGE_DISPARITY); } #endif /** * \brief Makes a deep copy of this image set. */ void copyTo(ImageSet& dest); /** * \brief Returns the number of bytes that are required to store one * image pixel. * * \param imageNumber The number of the image (0 ... getNumberOfImages()-1). */ int getBytesPerPixel(int imageNumber) const { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); return getBytesPerPixel(formats[imageNumber]); } /** * \brief Returns the number of bits that are required to store one * image pixel. * * \param imageNumber The number of the image (0 ... getNumberOfImages()-1). */ int getBitsPerPixel(int imageNumber) const { assert(imageNumber >= 0 && imageNumber < getNumberOfImages()); return getBitsPerPixel(formats[imageNumber]); } int getBitsPerPixel(ImageType what) const { int idx = getIndexOf(what, true); return getBitsPerPixel(idx); } static int getBitsPerPixel(ImageFormat format); /** * \brief Returns the number of bytes that are required to store one * image pixel with the given pixel format. */ static int getBytesPerPixel(ImageFormat format); /** * \brief Returns the number of images in this set */ int getNumberOfImages() const { return numberOfImages; } /** * \brief Sets the number of valid images in this set */ void setNumberOfImages(int number) { assert(number >= 1 && number <= MAX_SUPPORTED_IMAGES); numberOfImages = number; } /** * \brief Returns the ImageType of the specified channel */ ImageType getImageType(int imageNumber) const; /** * \brief Returns the index of a specific image type * * \param what ImageType of the desired channel. * \param throwIfNotFound Throw a runtime error instead of returning -1. * * \return Returns the index of the specified type, or -1 if not found. */ int getIndexOf(ImageType what, bool throwIfNotFound=false) const; /** * \brief Returns whether a left camera image is included in the enabled data */ bool hasImageType(ImageType what) const { return getIndexOf(what) >= 0; } /** * \brief Assign an image index to a specified ImageType, -1 to disable * * \param what The ImageType to assign a new image index to. * \param idx The index of the specified ImageType inside the data of * this ImageSet (-1 to disable). */ void setIndexOf(ImageType what, int idx); #ifdef CV_MAJOR_VERSION /** * \brief Converts one image of the set to an OpenCV image. * * \param imageNumber The number of the image that shall be converted * (0 ... getNumberOfImages()-1). * \param convertRgbToBgr If true, then color images will converted from * RGB to BGR in order to comply to OpenCV's convention. * * For this method to be available, the OpenCV headers need to be * included before including headers for libvisiontransfer. * * Please note that only a shallow copy is performed. The ImageSet object * must be kept alive for as long as the OpenCV image is in use. */ inline void toOpenCVImage(int imageNumber, cv::Mat& dest, bool convertRgbToBgr = true); #endif /** * \brief Sets the exposure time that was used for capturing the image set * * \param timeMicrosec Exposure time measured in microseconds */ void setExposureTime(int timeMicrosec) { exposureTime = timeMicrosec; } /** * \brief Gets the exposure time in microseconds that was used for * capturing the image set. * * \return Exposure time in microseconds */ int getExposureTime() const { return exposureTime; } /** * \brief Sets the timestamp of the last received sync pulse * \param seconds The time stamp with a resolution of one second. * \param microsec The fractional seconds part of the time stamp with * a resolution of 1 microsecond. */ void setLastSyncPulse(int seconds, int microsec) { lastSyncPulseSec = seconds; lastSyncPulseMicrosec = microsec; } /** * \brief Gets the timestamp of the last received sync pulse * * \param seconds The time stamp with a resolution of one second. * \param microsec The fractional seconds part of the time stamp with * a resolution of 1 microsecond. */ void getLastSyncPulse(int& seconds, int& microsec) const { seconds = lastSyncPulseSec; microsec = lastSyncPulseMicrosec; } private: // No pimpl idiom here as almost everything is inlined. int width; int height; int rowStride[MAX_SUPPORTED_IMAGES]; ImageFormat formats[MAX_SUPPORTED_IMAGES]; unsigned char* data[MAX_SUPPORTED_IMAGES]; const float* qMatrix; int timeSec; int timeMicrosec; unsigned int seqNum; int minDisparity; int maxDisparity; int subpixelFactor; int* referenceCounter; int numberOfImages; int indexLeftImage; int indexRightImage; int indexDisparityImage; int exposureTime; int lastSyncPulseSec; int lastSyncPulseMicrosec; void copyData(ImageSet& dest, const ImageSet& src, bool countRef); void decrementReference(); }; #ifndef DOXYGEN_SHOULD_SKIP_THIS // For source compatibility class DEPRECATED("Use ImageSet instead.") ImagePair: public ImageSet { }; #endif } // namespace #include "visiontransfer/imageset-opencv.h" #endif