cisstStereoVision Architecture
Multithreaded processing, see Thread Synchronization Macros
Example 5 - Filters with multithreaded processing
List of files
CMakeLists.txt: CMake script for creating compiler dependent projectsCMyFilter2.h: Custom filter 2 class declarationCMyFilter2.cpp: Custom filter 2 class definitionCMyFilter3.h: Custom filter 3 class declarationCMyFilter3.cpp: Custom filter 3 class definitionmain.cpp: Application entry point (main()function)
All files can be found under cisstStereoVision/examples/tutorial4.
Source code
CMake
cmake_minimum_required (VERSION 3.16)
# create a list of libraries needed for this project
set (REQUIRED_CISST_LIBRARIES cisstCommon cisstVector cisstOSAbstraction cisstMultiTask cisstStereoVision)
# find cisst and make sure the required libraries have been compiled
find_package (cisst REQUIRED ${REQUIRED_CISST_LIBRARIES})
if (cisst_FOUND)
add_executable (svlExTutorial4
CMyFilter2.h
CMyFilter2.cpp
CMyFilter3.h
CMyFilter3.cpp
main.cpp
)
set_property (TARGET svlExTutorial4 PROPERTY FOLDER "cisstStereoVision/examples")
target_link_libraries (svlExTutorial4 ${REQUIRED_CISST_LIBRARIES})
else (cisst_FOUND)
message ("Information: code in ${CMAKE_CURRENT_SOURCE_DIR} will not be compiled, it requires ${REQUIRED_CISST_LIBRARIES}")
endif (cisst_FOUND)
Custom filter 2 class declaration
#include <cisstStereoVision/svlFilterBase.h>
class CMyFilter2 : public svlFilterBase
{
public:
CMyFilter2();
protected:
int Initialize(svlSample* syncInput, svlSample* &syncOutput);
int Process(svlProcInfo* procInfo, svlSample* syncInput, svlSample* &syncOutput);
};
Custom filter 2 class implementation
#include "CMyFilter2.h"
CMyFilter2::CMyFilter2() :
svlFilterBase() // Call baseclass' constructor
{ //
AddInput("input", true); // Create synchronous input connector
AddInputType("input", svlTypeImageRGB); // Set sample type for input connector
//
AddOutput("output", true); // Create synchronous output connector
SetAutomaticOutputType(true); // Set output sample type the same as input sample type
}
int CMyFilter2::Initialize(svlSample* syncInput, svlSample* &syncOutput)
{
syncOutput = syncInput; // Pass the input sample forward to the output
return SVL_OK; //
}
int CMyFilter2::Process(svlProcInfo* procInfo, svlSample* syncInput, svlSample* &syncOutput)
{
svlSampleImageRGB* image = dynamic_cast<svlSampleImageRGB*>(syncInput); // Cast input sample to RGB image type
svlRGB* pixel = reinterpret_cast<svlRGB*>(image->GetUCharPointer()); // Get RGB pixel buffer for in-place modifications
unsigned int pixelcount = image->GetWidth() * image->GetHeight(); // Get number of pixels in image
unsigned int i, res; //
//
// for (i = 0; i < pixelcount; i ++)
_ParallelLoop(procInfo, i, pixelcount) //
{ //
res = pixel[i].r; // process data
res += pixel[i].g; //
res += pixel[i].b; //
res /= 3; //
pixel[i].r = pixel[i].g = pixel[i].b = res; //
} //
//
syncOutput = syncInput; // Pass the modified sample forward to the output
//
return SVL_OK; //
}
Custom filter 3 class declaration
#include <cisstStereoVision/svlFilterBase.h>
class CMyFilter3 : public svlFilterBase
{
public:
CMyFilter3();
protected:
int Initialize(svlSample* syncInput, svlSample* &syncOutput);
int Process(svlProcInfo* procInfo, svlSample* syncInput, svlSample* &syncOutput);
private:
unsigned int MaxVal;
};
Custom filter 3 class implementation
#include "CMyFilter3.h"
#include <cisstStereoVision/svlImageProcessing.h>
#include <cisstOSAbstraction/osaSleep.h>
CMyFilter3::CMyFilter3() :
svlFilterBase() // Call baseclass' constructor
{ //
AddInput("input", true); // Create synchronous input connector
AddInputType("input", svlTypeImageRGB); // Set sample type for input connector
//
AddOutput("output", true); // Create synchronous ouput connector
SetAutomaticOutputType(true); // Set output sample type the same as input sample type
}
int CMyFilter3::Initialize(svlSample* syncInput, svlSample* &syncOutput)
{
syncOutput = syncInput; // Pass the input sample forward to the output
return SVL_OK; //
}
int CMyFilter3::Process(svlProcInfo* procInfo, svlSample* syncInput, svlSample* &syncOutput)
{
svlSampleImageRGB* image = dynamic_cast<svlSampleImageRGB*>(syncInput); // Cast input sample to RGB image type
svlRGB* pixel = reinterpret_cast<svlRGB*>(image->GetUCharPointer()); // Get RGB pixel buffer for in-place modifications
unsigned int pixelcount = image->GetWidth() * image->GetHeight(); // Get number of pixels in image
unsigned int i, val; //
//
_OnSingleThread(procInfo) // Execute the following block on one thread only
{ //
osaSleep(1.0);
MaxVal = 0; // Find highest intensity pixel
for (i = 0; i < pixelcount; i ++) { //
val = (unsigned int)pixel[i].r + pixel[i].g + pixel[i].b; //
if (val >= MaxVal) MaxVal = val; //
} //
MaxVal /= 3; //
} //
//
_SynchronizeThreads(procInfo); // All threads wait until finished
//
if (MaxVal > 0) { //
svlSampleImage* subimage = image->GetSubImage(procInfo);
_CriticalSection(procInfo)
{
std::cerr << procInfo->ID << ", "
<< subimage->GetWidth() << ", " << subimage->GetHeight() << ", "
<< subimage->GetDataChannels() << ", " << subimage->GetBPP()
<< std::endl;
}
svlImageProcessing::Deinterlace(subimage, 0, svlImageProcessing::DI_Blending);
delete subimage;
} //
//
syncOutput = syncInput; // Pass the modified sample forward to the output
//
return SVL_OK; //
}
Main program
#include "CMyFilter2.h"
#include "CMyFilter3.h"
#include <cisstStereoVision/svlInitializer.h>
#include <cisstStereoVision/svlFilterOutput.h>
#include <cisstStereoVision/svlStreamManager.h>
#include <cisstStereoVision/svlFilterSourceVideoCapture.h>
#include <cisstStereoVision/svlFilterSplitter.h>
#include <cisstStereoVision/svlFilterImageWindow.h>
int main()
{
svlInitialize(); // Discover supported devices and codecs
//
svlStreamManager stream(2); // Instantiate SVL Stream
svlFilterSourceVideoCapture source(1); // Instantiate video capture filter
svlFilterSplitter splitter; // Instantiate splitter filter
CMyFilter2 filter2; // Instantiate user-implemented filter #2
CMyFilter3 filter3; // Instantiate user-implemented filter #3
svlFilterImageWindow window1; // Instantiate image window filter #1
svlFilterImageWindow window2; // Instantiate image window filter #2
//
source.SetDevice(0); // Select first available capture device
//
splitter.AddOutput("asyncbranch", 7, 3); // Add second output (async) to splitter
//
window1.SetTitle("Main branch"); // Assign title text to window filter #1
window2.SetTitle("Side branch"); // Assign title text to window filter #2
//
stream.SetSourceFilter(&source); // Assign source filter to stream
source.GetOutput()->Connect(splitter.GetInput()); // Connect source filter to splitter filter
splitter.GetOutput()->Connect(filter2.GetInput()); // Connect splitter filter to filter #2
splitter.GetOutput("asyncbranch")->Connect(filter3.GetInput()); // Connect splitter filter to filter #3
filter2.GetOutput()->Connect(window1.GetInput()); // Connect filter #2 to window #1
filter3.GetOutput()->Connect(window2.GetInput()); // Connect filter #3 to window #2
//
stream.Play(); // Initialize and Play video stream
//
char ch; //
std::cin >> ch; // (Wait for key-press)
//
stream.Release(); // Release stream
//
return 0; //
}