.. _program_listing_file_include_libcaercpp_events_frame.hpp: Program Listing for File frame.hpp ================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/libcaercpp/events/frame.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef LIBCAER_EVENTS_FRAME_HPP_ #define LIBCAER_EVENTS_FRAME_HPP_ #include "../../libcaer/events/frame.h" #include "../../libcaer/frame_utils.h" #include "common.hpp" // Separate define for getOpenCVMat() from main LIBCAER_HAVE_OPENCV, // which is for the frame utils support. LIBCAER_FRAMECPP_OPENCV_INSTALLED // is only for this one header here and the getOpenCVMat() functions, in // which case you need to have OpenCV installed for the application // using this only, not necessarily for libcaer. #ifndef LIBCAER_FRAMECPP_OPENCV_INSTALLED # define LIBCAER_FRAMECPP_OPENCV_INSTALLED LIBCAER_HAVE_OPENCV #endif #if defined(LIBCAER_FRAMECPP_OPENCV_INSTALLED) && LIBCAER_FRAMECPP_OPENCV_INSTALLED == 1 # include # include #endif namespace libcaer { namespace events { struct FrameEvent : public caer_frame_event { FrameEvent() = default; FrameEvent(const FrameEvent &rhs) = delete; FrameEvent &operator=(const FrameEvent &rhs) = delete; FrameEvent(FrameEvent &&rhs) = delete; FrameEvent &operator=(FrameEvent &&rhs) = delete; enum class colorChannels { GRAYSCALE = 1, RGB = 3, RGBA = 4, }; enum class colorFilter { MONO = 0, RGBG = 1, GRGB = 2, GBGR = 3, BGRG = 4, RGBW = 5, GRWB = 6, WBGR = 7, BWRG = 8, }; int32_t getTSStartOfFrame() const noexcept { return (caerFrameEventGetTSStartOfFrame(this)); } int64_t getTSStartOfFrame64(const EventPacket &packet) const noexcept { return (caerFrameEventGetTSStartOfFrame64( this, reinterpret_cast(packet.getHeaderPointer()))); } void setTSStartOfFrame(int32_t ts) { if (ts < 0) { throw std::invalid_argument("Negative timestamp not allowed."); } caerFrameEventSetTSStartOfFrame(this, ts); } int32_t getTSEndOfFrame() const noexcept { return (caerFrameEventGetTSEndOfFrame(this)); } int64_t getTSEndOfFrame64(const EventPacket &packet) const noexcept { return (caerFrameEventGetTSEndOfFrame64( this, reinterpret_cast(packet.getHeaderPointer()))); } void setTSEndOfFrame(int32_t ts) { if (ts < 0) { throw std::invalid_argument("Negative timestamp not allowed."); } caerFrameEventSetTSEndOfFrame(this, ts); } int32_t getTSStartOfExposure() const noexcept { return (caerFrameEventGetTSStartOfExposure(this)); } int64_t getTSStartOfExposure64(const EventPacket &packet) const noexcept { return (caerFrameEventGetTSStartOfExposure64( this, reinterpret_cast(packet.getHeaderPointer()))); } void setTSStartOfExposure(int32_t ts) { if (ts < 0) { throw std::invalid_argument("Negative timestamp not allowed."); } caerFrameEventSetTSStartOfExposure(this, ts); } int32_t getTSEndOfExposure() const noexcept { return (caerFrameEventGetTSEndOfExposure(this)); } int64_t getTSEndOfExposure64(const EventPacket &packet) const noexcept { return (caerFrameEventGetTSEndOfExposure64( this, reinterpret_cast(packet.getHeaderPointer()))); } void setTSEndOfExposure(int32_t ts) { if (ts < 0) { throw std::invalid_argument("Negative timestamp not allowed."); } caerFrameEventSetTSEndOfExposure(this, ts); } int32_t getTimestamp() const noexcept { return (caerFrameEventGetTimestamp(this)); } int64_t getTimestamp64(const EventPacket &packet) const noexcept { return ( caerFrameEventGetTimestamp64(this, reinterpret_cast(packet.getHeaderPointer()))); } int32_t getExposureLength() const noexcept { return (caerFrameEventGetExposureLength(this)); } bool isValid() const noexcept { return (caerFrameEventIsValid(this)); } void validate(EventPacket &packet) noexcept { caerFrameEventValidate(this, reinterpret_cast(packet.getHeaderPointer())); } void invalidate(EventPacket &packet) noexcept { caerFrameEventInvalidate(this, reinterpret_cast(packet.getHeaderPointer())); } uint8_t getROIIdentifier() const noexcept { return (caerFrameEventGetROIIdentifier(this)); } void setROIIdentifier(uint8_t roiIdent) noexcept { caerFrameEventSetROIIdentifier(this, roiIdent); } colorFilter getColorFilter() const noexcept { return (static_cast(caerFrameEventGetColorFilter(this))); } void setColorFilter(colorFilter cFilter) noexcept { caerFrameEventSetColorFilter(this, static_cast( static_cast::type>(cFilter))); } int32_t getLengthX() const noexcept { return (caerFrameEventGetLengthX(this)); } int32_t getLengthY() const noexcept { return (caerFrameEventGetLengthY(this)); } colorChannels getChannelNumber() const noexcept { return (static_cast(caerFrameEventGetChannelNumber(this))); } void setLengthXLengthYChannelNumber(int32_t lenX, int32_t lenY, colorChannels cNumber, const EventPacket &packet) { // Verify lengths and color channels number don't exceed allocated space. enum caer_frame_event_color_channels cNumberEnum = static_cast( static_cast::type>(cNumber)); if (lenX <= 0 || lenY <= 0 || cNumberEnum <= 0) { throw std::invalid_argument("Negative lengths or channel number not allowed."); } size_t neededMemory = (sizeof(uint16_t) * static_cast(lenX) * static_cast(lenY) * cNumberEnum); if (neededMemory > caerFrameEventPacketGetPixelsSize( reinterpret_cast(packet.getHeaderPointer()))) { throw std::invalid_argument("Given values result in memory usage higher than allocated frame event size."); } caerFrameEventSetLengthXLengthYChannelNumber( this, lenX, lenY, cNumberEnum, reinterpret_cast(packet.getHeaderPointer())); } size_t getPixelsMaxIndex() const noexcept { return (caerFrameEventGetPixelsMaxIndex(this)); } size_t getPixelsSize() const noexcept { return (caerFrameEventGetPixelsSize(this)); } int32_t getPositionX() const noexcept { return (caerFrameEventGetPositionX(this)); } void setPositionX(int32_t posX) noexcept { caerFrameEventSetPositionX(this, posX); } int32_t getPositionY() const noexcept { return (caerFrameEventGetPositionY(this)); } void setPositionY(int32_t posY) noexcept { caerFrameEventSetPositionY(this, posY); } uint16_t getPixel(int32_t xAddress, int32_t yAddress) const { // Check frame bounds first. if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(this)) { throw std::invalid_argument("Invalid Y address."); } int32_t xLength = caerFrameEventGetLengthX(this); if (xAddress < 0 || xAddress >= xLength) { throw std::invalid_argument("Invalid X address."); } // Get pixel value at specified position. return (le16toh(this->pixels[(yAddress * xLength) + xAddress])); } void setPixel(int32_t xAddress, int32_t yAddress, uint16_t pixelValue) { // Check frame bounds first. if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(this)) { throw std::invalid_argument("Invalid Y address."); } int32_t xLength = caerFrameEventGetLengthX(this); if (xAddress < 0 || xAddress >= xLength) { throw std::invalid_argument("Invalid X address."); } // Set pixel value at specified position. this->pixels[(yAddress * xLength) + xAddress] = htole16(pixelValue); } uint16_t getPixel(int32_t xAddress, int32_t yAddress, uint8_t channel) const { // Check frame bounds first. if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(this)) { throw std::invalid_argument("Invalid Y address."); } int32_t xLength = caerFrameEventGetLengthX(this); if (xAddress < 0 || xAddress >= xLength) { throw std::invalid_argument("Invalid X address."); } uint8_t channelNumber = caerFrameEventGetChannelNumber(this); if (channel >= channelNumber) { throw std::invalid_argument("Invalid channel number."); } // Get pixel value at specified position. return (le16toh(this->pixels[(((yAddress * xLength) + xAddress) * channelNumber) + channel])); } void setPixel(int32_t xAddress, int32_t yAddress, uint8_t channel, uint16_t pixelValue) { // Check frame bounds first. if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(this)) { throw std::invalid_argument("Invalid Y address."); } int32_t xLength = caerFrameEventGetLengthX(this); if (xAddress < 0 || xAddress >= xLength) { throw std::invalid_argument("Invalid X address."); } uint8_t channelNumber = caerFrameEventGetChannelNumber(this); if (channel >= channelNumber) { throw std::invalid_argument("Invalid channel number."); } // Set pixel value at specified position. this->pixels[(((yAddress * xLength) + xAddress) * channelNumber) + channel] = htole16(pixelValue); } uint16_t getPixelUnsafe(int32_t xAddress, int32_t yAddress) const noexcept { // Get pixel value at specified position. return (le16toh(this->pixels[(yAddress * caerFrameEventGetLengthX(this)) + xAddress])); } void setPixelUnsafe(int32_t xAddress, int32_t yAddress, uint16_t pixelValue) noexcept { // Set pixel value at specified position. this->pixels[(yAddress * caerFrameEventGetLengthX(this)) + xAddress] = htole16(pixelValue); } uint16_t getPixelUnsafe(int32_t xAddress, int32_t yAddress, uint8_t channel) const noexcept { uint8_t channelNumber = caerFrameEventGetChannelNumber(this); // Get pixel value at specified position. return (le16toh( this->pixels[(((yAddress * caerFrameEventGetLengthX(this)) + xAddress) * channelNumber) + channel])); } void setPixelUnsafe(int32_t xAddress, int32_t yAddress, uint8_t channel, uint16_t pixelValue) noexcept { uint8_t channelNumber = caerFrameEventGetChannelNumber(this); // Set pixel value at specified position. this->pixels[(((yAddress * caerFrameEventGetLengthX(this)) + xAddress) * channelNumber) + channel] = htole16(pixelValue); } uint16_t *getPixelArrayUnsafe() noexcept { return (this->pixels); } const uint16_t *getPixelArrayUnsafe() const noexcept { return (this->pixels); } #if defined(LIBCAER_FRAMECPP_OPENCV_INSTALLED) && LIBCAER_FRAMECPP_OPENCV_INSTALLED == 1 cv::Mat getOpenCVMat() noexcept { const cv::Size frameSize(caerFrameEventGetLengthX(this), caerFrameEventGetLengthY(this)); cv::Mat frameMat( frameSize, CV_16UC(caerFrameEventGetChannelNumber(this)), reinterpret_cast(this->pixels)); return (frameMat); } const cv::Mat getOpenCVMat(bool copyPixels = true) const noexcept { const cv::Size frameSize(caerFrameEventGetLengthX(this), caerFrameEventGetLengthY(this)); const cv::Mat frameMat(frameSize, CV_16UC(caerFrameEventGetChannelNumber(this)), reinterpret_cast(const_cast(this->pixels))); if (copyPixels) { return (frameMat.clone()); } else { return (frameMat); } } #endif }; static_assert(std::is_standard_layout::value, "FrameEvent is not of standard layout."); class FrameEventPacket : public EventPacketCommon { public: // Constructors. FrameEventPacket(size_type eventCapacity, int16_t eventSource, int32_t tsOverflow, int32_t maxLengthX, int32_t maxLengthY, int16_t maxChannelNumber) { constructorCheckCapacitySourceTSOverflow(eventCapacity, eventSource, tsOverflow); if (maxLengthX <= 0) { throw std::invalid_argument("Negative or zero maximum X length not allowed."); } if (maxLengthY <= 0) { throw std::invalid_argument("Negative or zero maximum Y length not allowed."); } if (maxChannelNumber <= 0) { throw std::invalid_argument("Negative or zero maximum number of channels not allowed."); } caerFrameEventPacket packet = caerFrameEventPacketAllocate( eventCapacity, eventSource, tsOverflow, maxLengthX, maxLengthY, maxChannelNumber); constructorCheckNullptr(packet); header = &packet->packetHeader; isMemoryOwner = true; // Always owner on new allocation! } FrameEventPacket(size_type eventCapacity, int16_t eventSource, int32_t tsOverflow, int32_t maxNumPixels, int16_t maxChannelNumber) { constructorCheckCapacitySourceTSOverflow(eventCapacity, eventSource, tsOverflow); if (maxNumPixels <= 0) { throw std::invalid_argument("Negative or zero maximum number of pixels not allowed."); } if (maxChannelNumber <= 0) { throw std::invalid_argument("Negative or zero maximum number of channels not allowed."); } caerFrameEventPacket packet = caerFrameEventPacketAllocateNumPixels( eventCapacity, eventSource, tsOverflow, maxNumPixels, maxChannelNumber); constructorCheckNullptr(packet); header = &packet->packetHeader; isMemoryOwner = true; // Always owner on new allocation! } FrameEventPacket(caerFrameEventPacket packet, bool takeMemoryOwnership = true) { constructorCheckNullptr(packet); constructorCheckEventType(&packet->packetHeader, FRAME_EVENT); header = &packet->packetHeader; isMemoryOwner = takeMemoryOwnership; } FrameEventPacket(caerEventPacketHeader packetHeader, bool takeMemoryOwnership = true) { constructorCheckNullptr(packetHeader); constructorCheckEventType(packetHeader, FRAME_EVENT); header = packetHeader; isMemoryOwner = takeMemoryOwnership; } protected: // Event access methods. reference virtualGetEvent(size_type index) noexcept override { caerFrameEvent evtBase = caerFrameEventPacketGetEvent(reinterpret_cast(header), index); FrameEvent *evt = static_cast(evtBase); return (*evt); } const_reference virtualGetEvent(size_type index) const noexcept override { caerFrameEventConst evtBase = caerFrameEventPacketGetEventConst(reinterpret_cast(header), index); const FrameEvent *evt = static_cast(evtBase); return (*evt); } public: size_t getPixelsSize() const noexcept { return (caerFrameEventPacketGetPixelsSize(reinterpret_cast(header))); } size_t getPixelsMaxIndex() const noexcept { return (caerFrameEventPacketGetPixelsMaxIndex(reinterpret_cast(header))); } enum class demosaicTypes { STANDARD = 0, TO_GRAY = 1, #if defined(LIBCAER_HAVE_OPENCV) && LIBCAER_HAVE_OPENCV == 1 OPENCV_STANDARD = 2, OPENCV_EDGE_AWARE = 3, OPENCV_TO_GRAY = 4, #endif }; std::unique_ptr demosaic(demosaicTypes demosaicType) const { std::unique_ptr outPacket(new FrameEventPacket( this->getEventValid(), this->getEventSource(), this->getEventTSOverflow(), this->getEventSize(), RGB)); size_t outIdx = 0; for (const auto &frame : *this) { // Only operate on valid frames. if (!frame.isValid()) { continue; } auto &outFrame = ((*outPacket)[outIdx]); // Copy header over. This will also copy validity information, so all copied frames are valid. memcpy(static_cast(&outFrame), &frame, (sizeof(struct caer_frame_event) - sizeof(uint16_t))); // Verify requirements for demosaicing operation. if ((frame.getChannelNumber() == libcaer::events::FrameEvent::colorChannels::GRAYSCALE) && (frame.getColorFilter() != libcaer::events::FrameEvent::colorFilter::MONO)) { #if defined(LIBCAER_HAVE_OPENCV) && LIBCAER_HAVE_OPENCV == 1 if ((demosaicType != demosaicTypes::TO_GRAY) && (demosaicType != demosaicTypes::OPENCV_TO_GRAY)) { #else if (demosaicType != demosaicTypes::TO_GRAY) { #endif // Change channel to RGB. If color requested. outFrame.setLengthXLengthYChannelNumber(frame.getLengthX(), frame.getLengthY(), libcaer::events::FrameEvent::colorChannels::RGB, *outPacket); } // Do interpolation. caerFrameUtilsDemosaic(&frame, &outFrame, static_cast( static_cast::type>(demosaicType))); } else { // Just copy data over. memcpy(outFrame.getPixelArrayUnsafe(), frame.getPixelArrayUnsafe(), frame.getPixelsSize()); } outIdx++; } // Set number of events in output packet correctly. outPacket->setEventNumber(outIdx); outPacket->setEventValid(outIdx); return (outPacket); } enum class contrastTypes { STANDARD = 0, #if defined(LIBCAER_HAVE_OPENCV) && LIBCAER_HAVE_OPENCV == 1 OPENCV_NORMALIZATION = 1, OPENCV_HISTOGRAM_EQUALIZATION = 2, OPENCV_CLAHE = 3, #endif }; void contrast(contrastTypes contrastType) noexcept { for (auto &frame : *this) { // Only operate on valid frames. if (!frame.isValid()) { continue; } caerFrameUtilsContrast(&frame, &frame, static_cast( static_cast::type>(contrastType))); } } }; } // namespace events } // namespace libcaer #endif /* LIBCAER_EVENTS_FRAME_HPP_ */