64 imageDimension = imageProviderInfo.
imageFormat.dimension;
68 cameraImages =
new CByteImage*[2];
79 visionx::StereoCalibrationProviderInterfacePrx calibrationProvider =
80 visionx::StereoCalibrationProviderInterfacePrx::checkedCast(imageProviderPrx);
82 if (calibrationProvider)
88 ARMARX_WARNING <<
"unable to obtain calibration parameters. using default values";
90 unitFactorX = (1.0 / 640.0) * (59.7);
91 unitFactorY = (1.0 / 480.0) * (44.775);
107 std::unique_lock lock(imageMutex);
111 ARMARX_WARNING <<
"Timeout while waiting for camera images (>1000ms)";
115 armarx::MetaInfoSizeBasePtr info;
125 IplImage* ppIplImages[1] = {IplImageAdaptor::Adapt(cameraImages[1])};
129 cv::Mat resultImage = cv::cvarrToMat(ppIplImages[0]);
130 cv::cvtColor(resultImage, grayImage, cv::COLOR_BGR2GRAY);
136 std::vector<cv::Point2f> features;
138 timeDiff = (info->timeProvided - previousTime) / 1000000.0;
140 if ((timeDiff > 1.0) || !previousFeatures.size())
144 ARMARX_INFO <<
"time delta is larger than 1 sec. discarding previous features.";
147 if (!previousFeatures.size())
149 ARMARX_INFO <<
"no feature found on previous image. discarding previous image.";
157 ComputeOpticalFlow(resultImage, grayImage);
164 prx->reportNewOpticalFlow(resultX, resultY, timeDiff, previousTime);
167 debugValues[
"x"] =
new Variant(resultX);
168 debugValues[
"y"] =
new Variant(resultY);
169 debugValues[
"delta_t"] =
new Variant((timeDiff));
172 debugObserver->setDebugChannel(
getName(), debugValues);
181 cv::Size size = cv::Size(chessboardWidth, chessboardHeight);
184 bool foundCorners = cv::findChessboardCorners(
185 grayImage, size, features, cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
187 cv::drawChessboardCorners(resultImage, size, features, foundCorners);
196 int maxCorners = 100;
197 double qualityLevel = 0.01;
198 double minDistance = 10.0;
201 bool useHarrisDetector =
true;
204 cv::goodFeaturesToTrack(grayImage,
217 cv::Mat flow = cv::Mat(grayImage.rows, grayImage.cols, CV_32FC1);
218 double mean_flow = 0.;
219 double rmse_flow = 0.;
222 if (previousImage.size() == grayImage.size())
224 cv::calcOpticalFlowFarneback(
225 previousImage, grayImage, flow, 0.5, 10, 45, 3, 9, 1.2, 0);
226 flow = (59.7 / 640.) * flow;
227 flow = (1.0 / timeDiff) * flow;
228 computeAverageDenseFlow(flow, mean_flow, rmse_flow);
233 drawDenseFlowMap(flow, resultImage, 10, CV_RGB(0, 255, 0));
237 debugValues[
"mean_dense"] =
new Variant((mean_flow));
238 debugValues[
"rmse_dense"] =
new Variant((rmse_flow));
239 debugObserver->setDebugChannel(
getName(), debugValues);
243 CByteImage* resultImages[1] = {IplImageAdaptor::Adapt(ppIplImages[0])};
248 if (!features.size())
255 previousImage = grayImage;
256 previousFeatures = features;
257 previousTime = info->timeProvided;
263 fpsCounter.assureFPS(frameRate);
268OpticalFlow::ComputeOpticalFlow(cv::Mat resultImage, cv::Mat grayImage)
270 std::vector<uchar>
status;
271 std::vector<float> error;
273 std::vector<cv::Point2f> trackedFeatures;
274 cv::calcOpticalFlowPyrLK(previousImage,
281 cv::OPTFLOW_USE_INITIAL_FLOW);
283 std::vector<float> avgDiffx, avgDiffy;
284 for (
size_t i = 0; i < trackedFeatures.size(); i++)
288 avgDiffx.push_back(previousFeatures[i].
x - trackedFeatures[i].
x);
289 avgDiffy.push_back(previousFeatures[i].y - trackedFeatures[i].y);
291 cv::circle(resultImage, previousFeatures[i], 2, CV_RGB(255, 0, 0), -1);
292 cv::circle(resultImage, trackedFeatures[i], 2, CV_RGB(0, 0, 255), -1);
293 cv::line(resultImage, previousFeatures[i], trackedFeatures[i], CV_RGB(255, 0, 0), 1);
302 for (
size_t i = 0; i < (avgDiffx.size() / 20); i++)
304 avgDiffx = removeHighestAndLowestMember(avgDiffx);
306 for (
size_t i = 0; i < (avgDiffy.size() / 20); i++)
308 avgDiffy = removeHighestAndLowestMember(avgDiffy);
312 if (!avgDiffx.size() || !avgDiffy.size())
314 ARMARX_WARNING <<
"No features found in the image, return = optical Flow!";
320 Eigen::Map<Eigen::ArrayXf> diffX(avgDiffx.data(), avgDiffx.size());
321 Eigen::Map<Eigen::ArrayXf> diffY(avgDiffy.data(), avgDiffy.size());
324 resultX = diffX.mean() / timeDiff;
325 resultY = diffY.mean() / timeDiff;
327 resultX *= unitFactorX;
328 resultY *= unitFactorY;
332OpticalFlow::removeHighestAndLowestMember(std::vector<float>& input)
334 std::sort(input.begin(), input.end());
335 return std::vector<float>(&input[1], &input[input.size() - 1]);
339OpticalFlow::drawDenseFlowMap(
const cv::Mat& flow,
342 const cv::Scalar& color)
345 for (
int y = 0; y < cflowmap.rows; y += step)
346 for (
int x = 0; x < cflowmap.cols; x += step)
348 const cv::Point2f& fxy = flow.at<cv::Point2f>(y, x);
351 cv::Point(cvRound(x + fxy.x), cvRound(y + fxy.y)),
353 cv::circle(cflowmap, cv::Point(cvRound(x + fxy.x), cvRound(y + fxy.y)), 1, color, -1);
359OpticalFlow::computeAverageDenseFlow(
const cv::Mat& flow,
double&
mean,
double& rmse)
367 for (
int y = round(flow.rows / 4); y < round(flow.rows * 3 / 4); y++)
369 for (
int x = round(flow.cols / 4); x < round(flow.cols * 3 / 4); x++)
371 const cv::Point2f& fxy = flow.at<cv::Point2f>(y, x);
372 d = fxy.x * fxy.x + fxy.y * fxy.y;
379 rmse =
sqrt(dist2 / count);
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
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.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
Brief description of class OpticalFlow.
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
void onExitImageProcessor() override
Exit the ImapeProcessor component.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
void onInitImageProcessor() override
Setup the vision component.
void reportStereoCalibrationChanged(const visionx::StereoCalibration &stereoCalibration, bool, const std::string &, const Ice::Current &c=Ice::emptyCurrent) override
static std::string GetDefaultName()
The Variant class is described here: Variants.
void enableResultImages(int numberImages, ImageDimension imageDimension, ImageType imageType, const std::string &name="")
Enables visualization.
void usingImageProvider(std::string name)
Registers a delayed topic subscription and a delayed provider proxy retrieval which all will be avail...
bool waitForImages(int milliseconds=1000)
Wait for new images.
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
int getImages(CByteImage **ppImages)
Poll images from provider.
void provideResultImages(CByteImage **images, armarx::MetaInfoSizeBasePtr info=nullptr)
sends result images for visualization
ImageFormatInfo imageFormat
Image format struct that contains all necessary image information.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
std::map< std::string, VariantBasePtr > StringVariantBaseMap
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.