Skip to content

Commit 989909a

Browse files
adamajijrojasUNC
andauthored
Allow Andor device to process acquisition on separate thread (#759)
* ENH: Allow Andor device to process acquisition on separate thread * ENH: Expose AbortAcquisition for Andor device * ENH: expose GetStatus and add method that returns if the camera is acquiring * BUG: change references of "distance" coefficients to "distortion" Co-authored-by: Juan Rojas <jrojas@sonovol.com>
1 parent 486a65b commit 989909a

2 files changed

Lines changed: 195 additions & 58 deletions

File tree

src/PlusDataCollection/Andor/vtkPlusAndorVideoSource.cxx

Lines changed: 159 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ vtkStandardNewMacro(vtkPlusAndorVideoSource);
1717

1818
// put these here so there is no public dependence on OpenCV
1919
cv::Mat cvCameraIntrinsics;
20-
cv::Mat cvDistanceCoefficients;
20+
cv::Mat cvDistortionCoefficients;
2121
cv::Mat cvBadPixelImage;
2222
cv::Mat cvFlatCorrection;
2323
cv::Mat cvBiasDarkCorrection;
@@ -45,7 +45,7 @@ void vtkPlusAndorVideoSource::PrintSelf(ostream& os, vtkIndent indent)
4545
os << indent << "SafeTemperature: " << SafeTemperature << std::endl;
4646
os << indent << "CurrentTemperature: " << CurrentTemperature << std::endl;
4747
os << indent << "CameraIntrinsics: " << cvCameraIntrinsics << std::endl;
48-
os << indent << "DistanceCoefficients: " << cvDistanceCoefficients << std::endl;
48+
os << indent << "DistortionCoefficients: " << cvDistortionCoefficients << std::endl;
4949
os << indent << "UseFrameCorrections: " << UseFrameCorrections << std::endl;
5050
os << indent << "UseCosmicRayCorrection: " << UseCosmicRayCorrection << std::endl;
5151
os << indent << "FlatCorrection: " << flatCorrection << std::endl;
@@ -134,13 +134,13 @@ PlusStatus vtkPlusAndorVideoSource::ReadConfiguration(vtkXMLDataElement* rootCon
134134
deviceConfig->GetVectorAttribute("HSSpeed", 2, HSSpeed);
135135
deviceConfig->GetVectorAttribute("OutputSpacing", 3, OutputSpacing);
136136
deviceConfig->GetVectorAttribute("CameraIntrinsics", 9, cameraIntrinsics);
137-
deviceConfig->GetVectorAttribute("DistanceCoefficients", 4, distanceCoefficients);
137+
deviceConfig->GetVectorAttribute("DistortionCoefficients", 4, distortionCoefficients);
138138
badPixelCorrection = deviceConfig->GetAttribute("BadPixelCorrection");
139139
flatCorrection = deviceConfig->GetAttribute("FlatCorrection");
140140
biasDarkCorrection = deviceConfig->GetAttribute("BiasDarkCorrection");
141141

142142
cvCameraIntrinsics = cv::Mat(3, 3, CV_64FC1, cameraIntrinsics);
143-
cvDistanceCoefficients = cv::Mat(1, 4, CV_64FC1, distanceCoefficients);
143+
cvDistortionCoefficients = cv::Mat(1, 4, CV_64FC1, distortionCoefficients);
144144
this->SetBadPixelCorrectionImage(badPixelCorrection); // load the image
145145
this->SetFlatCorrectionImage(flatCorrection); // load and normalize if needed
146146
this->SetBiasDarkCorrectionImage(biasDarkCorrection); // load the image
@@ -169,7 +169,7 @@ PlusStatus vtkPlusAndorVideoSource::WriteConfiguration(vtkXMLDataElement* rootCo
169169
deviceConfig->SetVectorAttribute("HSSpeed", 2, HSSpeed);
170170
deviceConfig->SetVectorAttribute("OutputSpacing", 3, OutputSpacing);
171171
deviceConfig->SetVectorAttribute("CameraIntrinsics", 9, cameraIntrinsics);
172-
deviceConfig->SetVectorAttribute("DistanceCoefficients", 4, distanceCoefficients);
172+
deviceConfig->SetVectorAttribute("DistortionCoefficients", 4, distortionCoefficients);
173173
deviceConfig->SetAttribute("FlatCorrection", flatCorrection.c_str());
174174
deviceConfig->SetAttribute("BiasDarkCorrection", biasDarkCorrection.c_str());
175175
deviceConfig->SetAttribute("BadPixelCorrection", badPixelCorrection.c_str());
@@ -367,6 +367,9 @@ PlusStatus vtkPlusAndorVideoSource::InternalDisconnect()
367367
// WaitForWarmup();
368368
// }
369369

370+
// in case we quit before an acquisition is complete, close the acquisition thread
371+
AbortAcquisition();
372+
370373
checkStatus(FreeInternalMemory(), "FreeInternalMemory");
371374

372375
unsigned result = checkStatus(ShutDown(), "ShutDown");
@@ -487,32 +490,26 @@ void vtkPlusAndorVideoSource::WaitForWarmup()
487490
}
488491

489492
// ----------------------------------------------------------------------------
490-
PlusStatus vtkPlusAndorVideoSource::AcquireFrame(float exposure, ShutterMode shutterMode, int binning, int vsSpeed, int hsSpeed)
493+
PlusStatus vtkPlusAndorVideoSource::AcquireFrame()
491494
{
492-
checkStatus(::SetExposureTime(exposure), "SetExposureTime");
493-
checkStatus(::SetShutter(1, shutterMode, 0, 0), "SetShutter");
494-
495-
int hbin = binning > 0 ? binning : this->HorizontalBins;
496-
int vbin = binning > 0 ? binning : this->VerticalBins;
497-
checkStatus(::SetImage(hbin, vbin, 1, 1024, 1, 1024), "Binning");
498-
AdjustBuffers(hbin, vbin);
499-
500-
AdjustSpacing(hbin, vbin);
501-
502-
int vsInd = vsSpeed >= 0 ? vsSpeed : this->VSSpeed;
503-
checkStatus(::SetVSSpeed(vsInd), "SetVSSpeed");
495+
checkStatus(::SetExposureTime(this->effectiveExpTime), "SetExposureTime");
496+
checkStatus(::SetShutter(1, this->effectiveShutter, 0, 0), "SetShutter");
497+
checkStatus(::SetImage(this->effectiveHBins, this->effectiveVBins, 1, 1024, 1, 1024), "Binning");
498+
checkStatus(::SetVSSpeed(this->effectiveVSInd), "SetVSSpeed");
499+
checkStatus(::SetHSSpeed(this->HSSpeed[0], this->effectiveHSInd), "SetHSSpeed");
504500

505-
int hsInd = hsSpeed >= 0 ? hsSpeed : this->HSSpeed[1];
506-
checkStatus(::SetHSSpeed(this->HSSpeed[0], hsInd), "SetHSSpeed");
501+
AdjustBuffers(this->effectiveHBins, this->effectiveVBins);
502+
AdjustSpacing(this->effectiveHBins, this->effectiveVBins);
507503

508504
unsigned rawFrameSize = frameSize[0] * frameSize[1];
509505
rawFrame.resize(rawFrameSize, 0);
510506

511507
checkStatus(StartAcquisition(), "StartAcquisition");
512508
unsigned result = checkStatus(WaitForAcquisition(), "WaitForAcquisition");
513-
if(result == DRV_NO_NEW_DATA) // Log a more specific log message for WaitForAcquisition
509+
if(result != DRV_SUCCESS)
514510
{
515-
LOG_ERROR("Non-Acquisition Event occurred.(e.g. CancelWait() called)");
511+
LOG_ERROR("Acquisition failed or cancelled.");
512+
return PLUS_FAIL;
516513
}
517514
this->currentTime = vtkIGSIOAccurateTimer::GetSystemTime();
518515

@@ -690,7 +687,7 @@ void vtkPlusAndorVideoSource::ApplyFrameCorrections(int binning, float exposureT
690687
}
691688

692689
// OpenCV's lens distortion correction
693-
cv::undistort(floatImage, result, cvCameraIntrinsics, cvDistanceCoefficients);
690+
cv::undistort(floatImage, result, cvCameraIntrinsics, cvDistortionCoefficients);
694691
LOG_INFO("Applied lens distortion correction");
695692

696693
// Divide the image by the 32-bit floating point correction image
@@ -703,53 +700,149 @@ void vtkPlusAndorVideoSource::ApplyFrameCorrections(int binning, float exposureT
703700
}
704701

705702
// ----------------------------------------------------------------------------
706-
PlusStatus vtkPlusAndorVideoSource::AcquireBLIFrame(int binning, int vsSpeed, int hsSpeed, float exposureTime)
703+
PlusStatus vtkPlusAndorVideoSource::StartBLIFrameAcquisition(int binning, int vsSpeed, int hsSpeed, float exposureTime)
704+
{
705+
if (this->threadID > -1)
706+
{
707+
LOG_ERROR("An acquisition thread is already running!");
708+
return PLUS_FAIL;
709+
}
710+
711+
this->effectiveHBins = binning > 0 ? binning : this->HorizontalBins;
712+
this->effectiveVBins = binning > 0 ? binning : this->VerticalBins;
713+
this->effectiveVSInd = vsSpeed > -1 ? vsSpeed : this->VSSpeed;
714+
this->effectiveHSInd = hsSpeed > -1 ? hsSpeed : this->HSSpeed[1];
715+
this->effectiveExpTime = exposureTime > -1 ? exposureTime : this->ExposureTime;
716+
this->effectiveShutter = ShutterMode::FullyAuto;
717+
718+
this->threadID = this->Threader->SpawnThread((vtkThreadFunctionType)&vtkPlusAndorVideoSource::AcquireBLIFrameThread, this);
719+
return PLUS_SUCCESS;
720+
}
721+
722+
// ----------------------------------------------------------------------------
723+
void* vtkPlusAndorVideoSource::AcquireBLIFrameThread(vtkMultiThreader::ThreadInfo* info)
707724
{
708-
WaitForCooldown();
709-
AcquireFrame(exposureTime, ShutterMode::FullyAuto, binning, vsSpeed, hsSpeed);
710-
++this->FrameNumber;
711-
AddFrameToDataSource(BLIRaw);
725+
vtkPlusAndorVideoSource* device = static_cast<vtkPlusAndorVideoSource*>(info->UserData);
712726

713-
if(this->UseFrameCorrections)
727+
device->WaitForCooldown();
728+
if (device->AcquireFrame() == PLUS_FAIL)
714729
{
715-
ApplyFrameCorrections(binning, exposureTime);
716-
AddFrameToDataSource(BLICorrected);
730+
device->threadID = -1;
731+
return NULL;
717732
}
733+
++device->FrameNumber;
734+
device->AddFrameToDataSource(device->BLIRaw);
718735

736+
if(device->UseFrameCorrections)
737+
{
738+
device->ApplyFrameCorrections(device->effectiveHBins, device->effectiveExpTime);
739+
device->AddFrameToDataSource(device->BLICorrected);
740+
}
741+
742+
device->threadID = -1;
743+
return NULL;
744+
}
745+
746+
// ----------------------------------------------------------------------------
747+
PlusStatus vtkPlusAndorVideoSource::StartGrayscaleFrameAcquisition(int binning, int vsSpeed, int hsSpeed, float exposureTime)
748+
{
749+
if (this->threadID > -1)
750+
{
751+
LOG_ERROR("An acquisition thread is already running!");
752+
return PLUS_FAIL;
753+
}
754+
755+
this->effectiveHBins = binning > 0 ? binning : this->HorizontalBins;
756+
this->effectiveVBins = binning > 0 ? binning : this->VerticalBins;
757+
this->effectiveVSInd = vsSpeed > -1 ? vsSpeed : this->VSSpeed;
758+
this->effectiveHSInd = hsSpeed > -1 ? hsSpeed : this->HSSpeed[1];
759+
this->effectiveExpTime = exposureTime > -1 ? exposureTime : this->ExposureTime;
760+
this->effectiveShutter = ShutterMode::FullyAuto;
761+
762+
this->threadID = this->Threader->SpawnThread((vtkThreadFunctionType)&vtkPlusAndorVideoSource::AcquireGrayscaleFrameThread, this);
719763
return PLUS_SUCCESS;
764+
720765
}
721766

722767
// ----------------------------------------------------------------------------
723-
PlusStatus vtkPlusAndorVideoSource::AcquireGrayscaleFrame(int binning, int vsSpeed, int hsSpeed, float exposureTime)
768+
void* vtkPlusAndorVideoSource::AcquireGrayscaleFrameThread(vtkMultiThreader::ThreadInfo* info)
724769
{
725-
WaitForCooldown();
726-
AcquireFrame(exposureTime, ShutterMode::FullyAuto, binning, vsSpeed, hsSpeed);
727-
++this->FrameNumber;
728-
AddFrameToDataSource(GrayRaw);
770+
vtkPlusAndorVideoSource* device = static_cast<vtkPlusAndorVideoSource*>(info->UserData);
771+
772+
device->WaitForCooldown();
773+
if (device->AcquireFrame() == PLUS_FAIL)
774+
{
775+
device->threadID = -1;
776+
return NULL;
777+
}
778+
++device->FrameNumber;
779+
device->AddFrameToDataSource(device->GrayRaw);
729780

730-
if(this->UseFrameCorrections)
781+
if(device->UseFrameCorrections)
731782
{
732-
ApplyFrameCorrections(binning, exposureTime);
733-
AddFrameToDataSource(GrayCorrected);
783+
device->ApplyFrameCorrections(device->effectiveHBins, device->effectiveExpTime);
784+
device->AddFrameToDataSource(device->GrayCorrected);
734785
}
735786

787+
device->threadID = -1;
788+
return NULL;
789+
}
790+
791+
// ----------------------------------------------------------------------------
792+
PlusStatus vtkPlusAndorVideoSource::StartCorrectionFrameAcquisition(const std::string correctionFilePath, ShutterMode shutter, int binning, int vsSpeed, int hsSpeed, float exposureTime)
793+
{
794+
if (this->threadID > -1)
795+
{
796+
LOG_ERROR("An acquisition thread is already running!");
797+
return PLUS_FAIL;
798+
}
799+
800+
this->effectiveHBins = binning > 0 ? binning : this->HorizontalBins;
801+
this->effectiveVBins = binning > 0 ? binning : this->VerticalBins;
802+
this->effectiveVSInd = vsSpeed > -1 ? vsSpeed : this->VSSpeed;
803+
this->effectiveHSInd = hsSpeed > -1 ? hsSpeed : this->HSSpeed[1];
804+
this->effectiveExpTime = exposureTime > -1 ? exposureTime : this->ExposureTime;
805+
this->effectiveShutter = ShutterMode::FullyAuto;
806+
this->saveCorrectionPath = correctionFilePath;
807+
808+
this->threadID = this->Threader->SpawnThread((vtkThreadFunctionType)&vtkPlusAndorVideoSource::AcquireCorrectionFrameThread, this);
736809
return PLUS_SUCCESS;
737810
}
738811

739812
// ----------------------------------------------------------------------------
740-
PlusStatus vtkPlusAndorVideoSource::AcquireCorrectionFrame(const std::string correctionFilePath, ShutterMode shutter, int binning, int vsSpeed, int hsSpeed, float exposureTime)
813+
void* vtkPlusAndorVideoSource::AcquireCorrectionFrameThread(vtkMultiThreader::ThreadInfo* info)
741814
{
742-
AcquireFrame(exposureTime, shutter, binning, vsSpeed, hsSpeed);
743-
++this->FrameNumber;
815+
vtkPlusAndorVideoSource* device = static_cast<vtkPlusAndorVideoSource*>(info->UserData);
744816

745-
cv::Mat cvIMG(frameSize[0], frameSize[1], CV_16UC1, &rawFrame[0]); // uses rawFrame as buffer
746-
if(this->UseFrameCorrections)
817+
if (device->AcquireFrame() == PLUS_FAIL)
747818
{
748-
CorrectBadPixels(binning, cvIMG);
819+
device->threadID = -1;
820+
return NULL;
821+
}
822+
++device->FrameNumber;
823+
824+
cv::Mat cvIMG(device->frameSize[0], device->frameSize[1], CV_16UC1, &(device->rawFrame[0])); // uses rawFrame as buffer
825+
if(device->UseFrameCorrections)
826+
{
827+
device->CorrectBadPixels(device->effectiveHBins, cvIMG);
749828
LOG_INFO("Applied bad pixel correction");
750829
}
751830

752-
cv::imwrite(correctionFilePath, cvIMG);
831+
cv::imwrite(device->saveCorrectionPath, cvIMG);
832+
device->threadID = -1;
833+
return NULL;
834+
}
835+
836+
//-----------------------------------------------------------------------------
837+
PlusStatus vtkPlusAndorVideoSource::AbortAcquisition()
838+
{
839+
checkStatus(::CancelWait(), "CancelWait");
840+
unsigned result = checkStatus(::AbortAcquisition(), "AbortAcquisition");
841+
if ((result != DRV_SUCCESS) && (result != DRV_IDLE))
842+
{
843+
LOG_ERROR("Unable to abort acquisition.");
844+
return PLUS_FAIL;
845+
}
753846
return PLUS_SUCCESS;
754847
}
755848

@@ -1012,17 +1105,17 @@ std::array<double, 9> vtkPlusAndorVideoSource::GetCameraIntrinsics()
10121105
}
10131106

10141107
// ----------------------------------------------------------------------------
1015-
PlusStatus vtkPlusAndorVideoSource::SetDistanceCoefficients(std::array<double, 4> coefficients)
1108+
PlusStatus vtkPlusAndorVideoSource::SetDistortionCoefficients(std::array<double, 4> coefficients)
10161109
{
1017-
std::copy(std::begin(coefficients), std::end(coefficients), this->distanceCoefficients);
1110+
std::copy(std::begin(coefficients), std::end(coefficients), this->distortionCoefficients);
10181111
return PLUS_SUCCESS;
10191112
}
10201113

10211114
// ----------------------------------------------------------------------------
1022-
std::array<double, 4> vtkPlusAndorVideoSource::GetDistanceCoefficients()
1115+
std::array<double, 4> vtkPlusAndorVideoSource::GetDistortionCoefficients()
10231116
{
10241117
std::array<double, 4> returnCoefficients;
1025-
std::copy(this->distanceCoefficients, this->distanceCoefficients + 4, std::begin(returnCoefficients));
1118+
std::copy(this->distortionCoefficients, this->distortionCoefficients + 4, std::begin(returnCoefficients));
10261119
return returnCoefficients;
10271120
}
10281121

@@ -1153,6 +1246,22 @@ int vtkPlusAndorVideoSource::GetSafeTemperature()
11531246
return this->SafeTemperature;
11541247
}
11551248

1249+
// ----------------------------------------------------------------------------
1250+
unsigned int vtkPlusAndorVideoSource::GetCCDStatus()
1251+
{
1252+
int status;
1253+
GetStatus(&status);
1254+
1255+
return status;
1256+
}
1257+
1258+
// ----------------------------------------------------------------------------
1259+
bool vtkPlusAndorVideoSource::IsCCDAcquiring()
1260+
{
1261+
int status = GetCCDStatus();
1262+
return status == DRV_ACQUIRING;
1263+
}
1264+
11561265
// ----------------------------------------------------------------------------
11571266
unsigned int vtkPlusAndorVideoSource::checkStatus(unsigned int returnStatus, std::string functionName)
11581267
{

0 commit comments

Comments
 (0)