Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions MMCore/CoreCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,18 @@ int CoreCallback::InsertImage(const MM::Device* caller, const unsigned char* buf

int CoreCallback::InsertImage(const MM::Device* caller, const unsigned char* buf, unsigned width, unsigned height, unsigned byteDepth, const Metadata* pMd, bool doProcess)
{
// Check if the camera is currently snapping an image, if its calling InsertImage,
// then its circumventing having its own buffer. This allows camera device adapters to
// not have to implement their own buffers, and can instead just copy data in directly.
{
std::shared_ptr<CameraInstance> camera = std::static_pointer_cast<CameraInstance>(core_->deviceManager_->GetDevice(caller));
if (camera->IsSnapping()) {
// Don't do any metadata or image processing, for consistency with the existing SnapImage()/GetImage() methods
camera->StoreSnappedImage(buf, width, height, byteDepth);
return DEVICE_OK;
}
}

try
{
Metadata md = AddCameraMetadata(caller, pMd);
Expand Down Expand Up @@ -283,6 +295,18 @@ int CoreCallback::InsertImage(const MM::Device* caller, const unsigned char* buf

int CoreCallback::InsertImage(const MM::Device* caller, const unsigned char* buf, unsigned width, unsigned height, unsigned byteDepth, unsigned nComponents, const Metadata* pMd, bool doProcess)
{
// Check if the camera is currently snapping an image, if its calling InsertImage,
// then its circumventing having its own buffer. This allows camera device adapters to
// not have to implement their own buffers, and can instead just copy data in directly.
{
std::shared_ptr<CameraInstance> camera = std::static_pointer_cast<CameraInstance>(core_->deviceManager_->GetDevice(caller));
if (camera->IsSnapping()) {
// Don't do any metadata or image processing, for consistency with the existing SnapImage()/GetImage() methods
camera->StoreSnappedImage(buf, width, height, byteDepth);
return DEVICE_OK;
}
}

try
{
Metadata md = AddCameraMetadata(caller, pMd);
Expand Down
59 changes: 55 additions & 4 deletions MMCore/Devices/CameraInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,42 @@
#include "CameraInstance.h"


int CameraInstance::SnapImage() { RequireInitialized(__func__); return GetImpl()->SnapImage(); }
const unsigned char* CameraInstance::GetImageBuffer() { RequireInitialized(__func__); return GetImpl()->GetImageBuffer(); }
const unsigned char* CameraInstance::GetImageBuffer(unsigned channelNr) { RequireInitialized(__func__); return GetImpl()->GetImageBuffer(channelNr); }
const unsigned int* CameraInstance::GetImageBufferAsRGB32() { RequireInitialized(__func__); return GetImpl()->GetImageBufferAsRGB32(); }
int CameraInstance::SnapImage() {
RequireInitialized(__func__);
isSnapping_.store(true);
multiChannelImageCounter_.store(0);
int ret = GetImpl()->SnapImage();
isSnapping_.store(false);
return ret;
}

const unsigned char* CameraInstance::GetImageBuffer() {
RequireInitialized(__func__);
const unsigned char* snappedPixels = snappedImage_.GetPixels(0);
if (snappedPixels != nullptr) {
return snappedPixels;
}
return GetImpl()->GetImageBuffer();
}

const unsigned char* CameraInstance::GetImageBuffer(unsigned channelNr) {
RequireInitialized(__func__);
const unsigned char* snappedPixels = snappedImage_.GetPixels(channelNr);
if (snappedPixels != nullptr) {
return snappedPixels;
}
return GetImpl()->GetImageBuffer(channelNr);
}

const unsigned int* CameraInstance::GetImageBufferAsRGB32() {
RequireInitialized(__func__);
const unsigned int* snappedPixels = reinterpret_cast<const unsigned int*>(snappedImage_.GetPixels(0));
if (snappedPixels != nullptr) {
return snappedPixels;
}
return GetImpl()->GetImageBufferAsRGB32();
}

unsigned CameraInstance::GetNumberOfComponents() const { RequireInitialized(__func__); return GetImpl()->GetNumberOfComponents(); }

std::string CameraInstance::GetComponentName(unsigned component)
Expand Down Expand Up @@ -154,3 +186,22 @@ int CameraInstance::StopExposureSequence() { RequireInitialized(__func__); retur
int CameraInstance::ClearExposureSequence() { RequireInitialized(__func__); return GetImpl()->ClearExposureSequence(); }
int CameraInstance::AddToExposureSequence(double exposureTime_ms) { RequireInitialized(__func__); return GetImpl()->AddToExposureSequence(exposureTime_ms); }
int CameraInstance::SendExposureSequence() const { RequireInitialized(__func__); return GetImpl()->SendExposureSequence(); }

bool CameraInstance::IsSnapping() const {
return isSnapping_.load();
}

void CameraInstance::StoreSnappedImage(const unsigned char* buf, unsigned width, unsigned height,
unsigned byteDepth) {
// If the buffer doesn't exist or has wrong dimensions, create/resize it
if (snappedImage_.Width() != width ||
snappedImage_.Height() != height ||
snappedImage_.Depth() != byteDepth) {
snappedImage_.Resize(width, height, byteDepth);
}

// For multi-channel cameras, insertImage will be called once for each channel
snappedImage_.SetPixels(multiChannelImageCounter_.load(), buf);
multiChannelImageCounter_.fetch_add(1);

}
18 changes: 18 additions & 0 deletions MMCore/Devices/CameraInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#pragma once

#include "DeviceInstanceBase.h"
#include <atomic>
#include "../FrameBuffer.h"


class CameraInstance : public DeviceInstanceBase<MM::Camera>
Expand Down Expand Up @@ -82,4 +84,20 @@ class CameraInstance : public DeviceInstanceBase<MM::Camera>
int ClearExposureSequence();
int AddToExposureSequence(double exposureTime_ms);
int SendExposureSequence() const;

/**
* Checks if the camera is currently snapping an image.
* Thread-safe method that can be called from any thread.
* @return true if the camera is currently snapping an image, false otherwise
*/
bool IsSnapping() const;
void StoreSnappedImage(const unsigned char* buf, unsigned width, unsigned height, unsigned byteDepth);

private:
// Atomic flag to track if the camera is currently snapping an image
std::atomic<bool> isSnapping_{false};

// Frame buffer to store captured images
mm::FrameBuffer snappedImage_;
std::atomic<int> multiChannelImageCounter_{0};
};