63 imageDimension = imageProviderInfo.
imageFormat.dimension;
67 cameraImages =
new CByteImage*[2];
78 visionx::StereoCalibrationProviderInterfacePrx calibrationProvider =
79 visionx::StereoCalibrationProviderInterfacePrx::checkedCast(imageProviderPrx);
81 if (calibrationProvider)
87 ARMARX_WARNING <<
"unable to obtain calibration parameters. using default values";
89 unitFactorX = (1.0 / 640.0) * (59.7);
90 unitFactorY = (1.0 / 480.0) * (44.775);
106 std::unique_lock lock(imageMutex);
110 ARMARX_WARNING <<
"Timeout while waiting for camera images (>1000ms)";
114 armarx::MetaInfoSizeBasePtr info;
124 IplImage* ppIplImages[1] = {IplImageAdaptor::Adapt(cameraImages[1])};
128 cv::Mat resultImage = cv::cvarrToMat(ppIplImages[0]);
129 cv::cvtColor(resultImage, grayImage, cv::COLOR_BGR2GRAY);
135 std::vector<cv::Point2f> features;
137 timeDiff = (info->timeProvided - previousTime) / 1000000.0;
139 if ((timeDiff > 1.0) || !previousFeatures.size())
143 ARMARX_INFO <<
"time delta is larger than 1 sec. discarding previous features.";
146 if (!previousFeatures.size())
148 ARMARX_INFO <<
"no feature found on previous image. discarding previous image.";
156 ComputeOpticalFlow(resultImage, grayImage);
163 prx->reportNewOpticalFlow(resultX, resultY, timeDiff, previousTime);
166 debugValues[
"x"] =
new Variant(resultX);
167 debugValues[
"y"] =
new Variant(resultY);
168 debugValues[
"delta_t"] =
new Variant((timeDiff));
171 debugObserver->setDebugChannel(
getName(), debugValues);
180 cv::Size size = cv::Size(chessboardWidth, chessboardHeight);
183 bool foundCorners = cv::findChessboardCorners(
184 grayImage, size, features, cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
186 cv::drawChessboardCorners(resultImage, size, features, foundCorners);
195 int maxCorners = 100;
196 double qualityLevel = 0.01;
197 double minDistance = 10.0;
200 bool useHarrisDetector =
true;
203 cv::goodFeaturesToTrack(grayImage,
216 cv::Mat flow = cv::Mat(grayImage.rows, grayImage.cols, CV_32FC1);
217 double mean_flow = 0.;
218 double rmse_flow = 0.;
221 if (previousImage.size() == grayImage.size())
223 cv::calcOpticalFlowFarneback(
224 previousImage, grayImage, flow, 0.5, 10, 45, 3, 9, 1.2, 0);
225 flow = (59.7 / 640.) * flow;
226 flow = (1.0 / timeDiff) * flow;
227 computeAverageDenseFlow(flow, mean_flow, rmse_flow);
232 drawDenseFlowMap(flow, resultImage, 10, CV_RGB(0, 255, 0));
236 debugValues[
"mean_dense"] =
new Variant((mean_flow));
237 debugValues[
"rmse_dense"] =
new Variant((rmse_flow));
238 debugObserver->setDebugChannel(
getName(), debugValues);
242 CByteImage* resultImages[1] = {IplImageAdaptor::Adapt(ppIplImages[0])};
247 if (!features.size())
254 previousImage = grayImage;
255 previousFeatures = features;
256 previousTime = info->timeProvided;
262 fpsCounter.assureFPS(frameRate);
267OpticalFlow::ComputeOpticalFlow(cv::Mat resultImage, cv::Mat grayImage)
269 std::vector<uchar>
status;
270 std::vector<float> error;
272 std::vector<cv::Point2f> trackedFeatures;
273 cv::calcOpticalFlowPyrLK(previousImage,
280 cv::OPTFLOW_USE_INITIAL_FLOW);
282 std::vector<float> avgDiffx, avgDiffy;
283 for (
size_t i = 0; i < trackedFeatures.size(); i++)
287 avgDiffx.push_back(previousFeatures[i].
x - trackedFeatures[i].
x);
288 avgDiffy.push_back(previousFeatures[i].y - trackedFeatures[i].y);
290 cv::circle(resultImage, previousFeatures[i], 2, CV_RGB(255, 0, 0), -1);
291 cv::circle(resultImage, trackedFeatures[i], 2, CV_RGB(0, 0, 255), -1);
292 cv::line(resultImage, previousFeatures[i], trackedFeatures[i], CV_RGB(255, 0, 0), 1);
301 for (
size_t i = 0; i < (avgDiffx.size() / 20); i++)
303 avgDiffx = removeHighestAndLowestMember(avgDiffx);
305 for (
size_t i = 0; i < (avgDiffy.size() / 20); i++)
307 avgDiffy = removeHighestAndLowestMember(avgDiffy);
311 if (!avgDiffx.size() || !avgDiffy.size())
313 ARMARX_WARNING <<
"No features found in the image, return = optical Flow!";
319 Eigen::Map<Eigen::ArrayXf> diffX(avgDiffx.data(), avgDiffx.size());
320 Eigen::Map<Eigen::ArrayXf> diffY(avgDiffy.data(), avgDiffy.size());
323 resultX = diffX.mean() / timeDiff;
324 resultY = diffY.mean() / timeDiff;
326 resultX *= unitFactorX;
327 resultY *= unitFactorY;
331OpticalFlow::removeHighestAndLowestMember(std::vector<float>& input)
333 std::sort(input.begin(), input.end());
334 return std::vector<float>(&input[1], &input[input.size() - 1]);
338OpticalFlow::drawDenseFlowMap(
const cv::Mat& flow,
341 const cv::Scalar& color)
344 for (
int y = 0; y < cflowmap.rows; y += step)
345 for (
int x = 0; x < cflowmap.cols; x += step)
347 const cv::Point2f& fxy = flow.at<cv::Point2f>(y, x);
350 cv::Point(cvRound(x + fxy.x), cvRound(y + fxy.y)),
352 cv::circle(cflowmap, cv::Point(cvRound(x + fxy.x), cvRound(y + fxy.y)), 1, color, -1);
358OpticalFlow::computeAverageDenseFlow(
const cv::Mat& flow,
double&
mean,
double& rmse)
366 for (
int y = round(flow.rows / 4); y < round(flow.rows * 3 / 4); y++)
368 for (
int x = round(flow.cols / 4); x < round(flow.cols * 3 / 4); x++)
370 const cv::Point2f& fxy = flow.at<cv::Point2f>(y, x);
371 d = fxy.x * fxy.x + fxy.y * fxy.y;
378 rmse =
sqrt(dist2 / count);
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)
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
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.