Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV displaying a 2-channel image (optical flow)

I have optical flow stored in a 2-channel 32F matrix. I want to visualize the contents, what's the easiest way to do this?

How do I convert a CV_32FC2 to RGB with an empty blue channel, something imshow can handle? I am using OpenCV 2 C++ API.

Super Bonus Points

Ideally I would get the angle of flow in hue and the magnitude in brightness (with saturation at a constant 100%).

like image 940
Matt Montag Avatar asked Oct 07 '11 22:10

Matt Montag


2 Answers

imshow can handle only 1-channel gray-scale and 3-4 channel BRG/BGRA images. So you need do a conversion yourself.

I think you can do something similar to:

//extraxt x and y channels
cv::Mat xy[2]; //X,Y
cv::split(flow, xy);

//calculate angle and magnitude
cv::Mat magnitude, angle;
cv::cartToPolar(xy[0], xy[1], magnitude, angle, true);

//translate magnitude to range [0;1]
double mag_max;
cv::minMaxLoc(magnitude, 0, &mag_max);
magnitude.convertTo(magnitude, -1, 1.0 / mag_max);

//build hsv image
cv::Mat _hsv[3], hsv;
_hsv[0] = angle;
_hsv[1] = cv::Mat::ones(angle.size(), CV_32F);
_hsv[2] = magnitude;
cv::merge(_hsv, 3, hsv);

//convert to BGR and show
cv::Mat bgr;//CV_32FC3 matrix
cv::cvtColor(hsv, bgr, cv::COLOR_HSV2BGR);
cv::imshow("optical flow", bgr);

cv::waitKey(0);
like image 156
Andrey Kamaev Avatar answered Oct 14 '22 19:10

Andrey Kamaev


The MPI Sintel Dataset provides C and MatLab code for visualizing computed flow. Download the ground truth optical flow of the training set from here. The archive contains a folder flow_code containing the mentioned source code.

You can port the code to OpenCV, however, I wrote a simple OpenCV wrapper to easily use the provided code. Note that the method MotionToColor is taken from the color_flow.cpp file. Note the comments in the listing below.

// Important to include this before flowIO.h!
#include "imageLib.h"
#include "flowIO.h"
#include "colorcode.h"
// I moved the MotionToColor method in a separate header file.
#include "motiontocolor.h"

cv::Mat flow;
// Compute optical flow (e.g. using OpenCV); result should be
// 2-channel float matrix.

assert(flow.channels() == 2);
// assert(flow.type() == CV_32F);

int rows = flow.rows;
int cols = flow.cols;

CFloatImage cFlow(cols, rows, 2);

// Convert flow to CFLoatImage:
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        cFlow.Pixel(j, i, 0) = flow.at<cv::Vec2f>(i, j)[0];
        cFlow.Pixel(j, i, 1) = flow.at<cv::Vec2f>(i, j)[1];
    }
}

CByteImage cImage;
MotionToColor(cFlow, cImage, max);

cv::Mat image(rows, cols, CV_8UC3, cv::Scalar(0, 0, 0));

// Compute back to cv::Mat with 3 channels in BGR:
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        image.at<cv::Vec3b>(i, j)[0] = cImage.Pixel(j, i, 0);
        image.at<cv::Vec3b>(i, j)[1] = cImage.Pixel(j, i, 1);
        image.at<cv::Vec3b>(i, j)[2] = cImage.Pixel(j, i, 2);
    }
}

// Display or output the image ...

Below is the result when using the Optical Flow code and example images provided by Ce Liu.

Example images provided by Ce Liu.

Optical flow computed using the implementation provided by Ce Liu.

like image 31
David Stutz Avatar answered Oct 14 '22 17:10

David Stutz