34#include <opencv2/opencv.hpp>
37#include <SimoxUtility/algorithm.h>
57 if (numberImages == 0)
59 return armarx::Blob();
68 if (numberImages == 0)
70 return armarx::Blob();
99 setImageFormat(ImageDimension(640, 480), eBayerPattern, eBayerPatternRg);
115 if (numberImages != 0)
117 armarx::MetaInfoSizeBasePtr info(
new armarx::MetaInfoSizeBase(
168 if (numberImages != 0)
182 <<
" Did you forget to set call setNumberImages and setImageFormat in "
183 "onInitImageProvider?";
193 info =
new armarx::MetaInfoSizeBase(
194 imageFormat.dimension.width * imageFormat.dimension.height *
195 imageFormat.bytesPerPixel,
196 imageFormat.dimension.width * imageFormat.dimension.height *
197 imageFormat.bytesPerPixel,
220 Ice::Int compressionQuality,
221 armarx::MetaInfoSizeBasePtr& info,
225 switch (imageFormat.type)
234 throw armarx::LocalException()
235 <<
"unsupported image type " << (int)(imageFormat.type);
245 if (numberImages == 0)
247 return armarx::Blob();
251 auto imageTimestamp = IceUtil::Time::microSeconds(info->timeProvided);
252 auto key = std::make_pair(compressionType, compressionQuality);
254 std::unique_lock lock2(compressionDataMapMutex);
255 if (compressionDataMap.count(key) &&
256 compressionDataMap.at(key).imageTimestamp == imageTimestamp)
259 return compressionDataMap.at(key).compressedImage;
261 cv::Mat mat(imageFormat.dimension.height * numberImages,
262 imageFormat.dimension.width,
267 armarx::Blob encodedImg;
269 std::vector<int> compression_params;
270 std::string extension;
271 switch (compressionType)
275 compression_params = {cv::IMWRITE_PNG_COMPRESSION,
277 cv::IMWRITE_PNG_STRATEGY,
278 cv::IMWRITE_PNG_STRATEGY_RLE};
282 compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
283 compression_params.push_back(compressionQuality);
286 throw armarx::LocalException()
287 <<
"unsupported image type " << (int)(imageFormat.type);
289 cv::imencode(
"*" + extension, mat, encodedImg, compression_params);
291 compressionDataMap[key] = {encodedImg, imageTimestamp};
295 << imageFormat.dimension.height * numberImages * imageFormat.dimension.width *
296 imageFormat.bytesPerPixel
297 <<
" size after: " << encodedImg.size();
307 BayerPatternType bayerPatternType)
310 imageFormat.dimension = imageDimension;
311 imageFormat.type = imageType;
312 imageFormat.bpType = bayerPatternType;
318 imageFormat.bytesPerPixel = 1;
322 imageFormat.bytesPerPixel = 3;
326 imageFormat.bytesPerPixel = 4;
329 case eFloat3Channels:
330 imageFormat.bytesPerPixel = 12;
334 imageFormat.bytesPerPixel = 12;
337 case eColoredPointsScan:
338 imageFormat.bytesPerPixel = 16;
347 this->numberImages = numberImages;
354 if (numberImages == 0)
356 ARMARX_INFO <<
"Number of images is 0 - thus none can be provided";
361 imageFormat.dimension.width * imageFormat.dimension.height * imageFormat.bytesPerPixel;
371 if (imageTimestamp > IceUtil::Time())
375 for (
int i = 0; i < numberImages; i++)
392 <<
"imageProcessorProxy is NULL - could not report Image available";
400 if (numberImages == 0)
402 ARMARX_INFO <<
"Number of images is 0 - thus none can be provided";
409 for (
int i = 0; i < numberImages; i++)
420 const IceUtil::Time& imageTimestamp)
423 if (numberImages == 0)
425 ARMARX_INFO <<
"Number of images is 0 - thus none can be provided";
432 for (
int i = 0; i < numberImages; i++)
445 if (numberImages == 0)
447 ARMARX_INFO <<
"Number of images is 0 - thus none can be provided";
454 for (
int i = 0; i < numberImages; i++)
468 imageFormat.dimension.width * imageFormat.dimension.height * imageFormat.bytesPerPixel;
470 const bool is_recording = [&]
474 std::scoped_lock l{rec.statusMutex};
476 if (rec.status.type == imrec::State::stopping)
478 rec.status.type = imrec::State::writing;
483 return rec.status.type == imrec::State::running;
490 std::chrono::microseconds
timestamp{image_timestamp.toMicroSeconds()};
491 std::unordered_map<int, CByteImage*> current_frames;
492 for (
int i = 0; i < numberImages; ++i)
494 if (not rec.config.channelConfigs[i].disabled)
497 std::memcpy(current_frames[i]->pixels,
imageBuffers[i], imageSize);
503 std::scoped_lock l{rec.bufferMutex};
504 rec.buffer.push_back({
timestamp, current_frames});
519 <<
"Must supply same number of channel configs as there are channels";
521 std::scoped_lock l{rec.callMutex};
524 std::scoped_lock l{rec.statusMutex};
526 auto are_disabled = [](
const auto&
c) {
return c.disabled; };
530 if (rec.status.type != imrec::State::ready or
531 std::all_of(cfg.channelConfigs.begin(), cfg.channelConfigs.end(), are_disabled))
536 rec.status.framesWritten = 0;
537 rec.status.framesBuffered = 0;
538 rec.status.type = imrec::State::scheduled;
542 rec.config.name = simox::alg::replace_all(
549 rec.runningTask->start();
561 std::scoped_lock l{rec.statusMutex};
570 std::scoped_lock l{rec.callMutex};
573 std::scoped_lock l{rec.statusMutex};
577 if (rec.status.type != imrec::State::scheduled and
578 rec.status.type != imrec::State::running)
583 rec.status.type = imrec::State::stopping;
588 const bool join =
true;
589 rec.runningTask->stop(join);
606 const imrec::State state = [&]
608 std::scoped_lock l{rec.statusMutex};
609 return rec.status.type;
613 if (state == imrec::State::ready)
622 else if (state == imrec::State::scheduled)
626 const IceUtil::Time start_at =
627 IceUtil::Time::microSeconds(rec.config.startTimestamp);
628 const IceUtil::Time now = IceUtil::Time::now();
633 const std::filesystem::path path =
635 rec.channelRecordings.clear();
636 for (
int i = 0; i < numberImages; ++i)
638 const imrec::ChannelConfig& channel_cfg = rec.config.channelConfigs[i];
639 if (not channel_cfg.disabled)
642 const std::string name =
getName() +
"_" + channel_cfg.name;
645 path / rec.config.name, name, format, channel_cfg.fps);
647 r->writeMetadataDatetime(
648 "recording_manager_time",
649 std::chrono::microseconds{rec.config.startTimestamp});
650 r->writeMetadataLine(
"image_provider_name",
"string",
getName());
651 r->writeMetadataLine(
"channel_name",
"string", channel_cfg.name);
652 rec.channelRecordings[i] = r;
658 std::scoped_lock l{rec.statusMutex};
659 rec.status.type = imrec::State::running;
669 bool write_frames =
false;
671 std::unordered_map<int, CByteImage*> frames;
676 std::scoped_lock l{rec.bufferMutex, rec.statusMutex};
677 if (not rec.buffer.empty())
679 std::tie(
timestamp, frames) = rec.buffer.front();
680 rec.buffer.pop_front();
683 rec.status.framesBuffered =
static_cast<long>(rec.buffer.size());
684 ++rec.status.framesWritten;
691 if (state == imrec::State::writing)
693 ARMARX_DEBUG <<
"Buffer fully written to disk, exiting.";
694 rec.status.type = imrec::State::ready;
703 for (
auto& [i, frame] : frames)
713 else if (state == imrec::State::running)
715 std::unique_lock l{rec.bufferMutex};
717 rec.cv.wait(l, [&] {
return not rec.buffer.empty(); });
730 for (
auto& [i, r] : rec.channelRecordings)
734 rec.channelRecordings.clear();
742 std::vector<imrec::ChannelPreferences>
747 std::vector<imrec::ChannelPreferences> default_names;
748 imrec::ChannelPreferences cp;
749 cp.requiresLossless =
false;
750 for (
int i = 0; i < numberImages; ++i)
752 cp.name =
"c" + std::to_string(i);
753 default_names.push_back(cp);
755 return default_names;
The IceSharedMemoryProvider provides data via Ice or shared memory.
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
std::string getName() const
Retrieve name of object.
std::filesystem::path toSystemPath() const
Represents a point in time.
virtual void onExitImageProvider()=0
This is called when the Component::onExitComponent() setup is called.
void onInitComponent() override
void imageRecordingRunningTask()
armarx::Blob getImagesAndMetaInfo(armarx::MetaInfoSizeBasePtr &, const Ice::Current &) override
virtual void onDisconnectImageProvider()
void onDisconnectComponent() override
Hook for subclass.
void recordImages(const IceUtil::Time &image_timestamp)
armarx::IceSharedMemoryProvider< unsignedchar >::pointer_type sharedMemoryProvider
shared memory provider
virtual void onInitImageProvider()=0
This is called when the Component::onInitComponent() is called.
void updateTimestamp(Ice::Long timestamp, bool threadSafe=true)
Updates the timestamp of the currently captured image.
ImageFormatInfo getImageFormat(const Ice::Current &c=Ice::emptyCurrent) override
Returns the entire image format info struct via Ice.
void setImageFormat(ImageDimension imageDimension, ImageType imageType, BayerPatternType bayerPatternType=visionx::eBayerPatternRg)
Sets the image basic format data.
bool startImageRecording(const imrec::Config &cfg, const Ice::Current &) override
bool stopImageRecording(const Ice::Current &) override
int getNumberImages(const Ice::Current &c=Ice::emptyCurrent) override
Retrieve number of images handled by this provider.
virtual void onConnectImageProvider()
This is called when the Component::onConnectComponent() setup is called.
void provideImages(void **inputBuffers, const IceUtil::Time &imageTimestamp=IceUtil::Time())
send images raw.
void onConnectComponent() override
void setNumberImages(int numberImages)
Sets the number of images on each capture.
void ** imageBuffers
Image buffer memory.
armarx::SharedMemoryScopedWriteLockPtr getScopedWriteLock()
Retrieve scoped lock for writing to the memory.
std::vector< imrec::ChannelPreferences > getImageRecordingChannelPreferences(const Ice::Current &) override
ImageProcessorInterfacePrx imageProcessorProxy
Ice proxy of the image processor interface.
armarx::Blob getImages(const Ice::Current &c=Ice::emptyCurrent) override
Retrieve images via Ice.
void onExitComponent() override
imrec::Status getImageRecordingStatus(const Ice::Current &) override
armarx::Blob getCompressedImagesAndMetaInfo(CompressionType, Ice::Int compressionQuality, armarx::MetaInfoSizeBasePtr &info, const Ice::Current &) override
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::shared_ptr< SharedMemoryScopedWriteLock > SharedMemoryScopedWriteLockPtr
std::string datetime_to_string(std::chrono::microseconds ts)
visionx::imrec::Recording newRecording(const std::filesystem::path &path, const std::string &name, const Format format, double fps)
Format str2format(const std::string &format_str)
Format
Supported recording Formats.
std::shared_ptr< AbstractRecordingStrategy > Recording
Convenience alias for any recording strategy.