voiddrawArrow(cv::Mat& img, cv::Point pStart, cv::Point pEnd, int len, int alpha, cv::Scalar& color, int thickness){ constdouble PI = 3.1415926; Point arrow; double angle = atan2((double)(pStart.y - pEnd.y), (double)(pStart.x - pEnd.x)); line(img, pStart, pEnd, color, thickness); arrow.x = pEnd.x + len * cos(angle + PI * alpha / 180); arrow.y = pEnd.y + len * sin(angle + PI * alpha / 180); line(img, pEnd, arrow, color, thickness); arrow.x = pEnd.x + len * cos(angle - PI * alpha / 180); arrow.y = pEnd.y + len * sin(angle - PI * alpha / 180); line(img, pEnd, arrow, color, thickness); }
voiddrawLines(Mat flow, Mat &target){ // By y += 5, x += 5 you can specify the grid for (int y = 0; y < target.rows; y += 10) { for (int x = 0; x < target.cols; x += 10) { Vec2f flow_at_point = flow.at<Vec2f>(y, x); float fx = flow_at_point[0]; float fy = flow_at_point[1]; if ((fabs(fx) > UNKNOWN_FLOW_THRESH) || (fabs(fy) > UNKNOWN_FLOW_THRESH)) continue; // get the flow from y, x position * 10 for better visibility const Point2f flowatxy = flow.at<Point2f>(y, x) * 2;
// draw initial point //circle(target, Point(x, y), 1, Scalar(255, 0, 0), -1); // draw line at flow direction Point startP = Point(x, y); Point endP = Point(cvRound(x + flowatxy.x), cvRound(y + flowatxy.y)); if (startP == endP) continue; line(target, startP, endP, Scalar(255, 0, 0), 1); // draw arrow drawArrow(target, startP, endP, 5, 30, Scalar(255, 0, 0), 1); } } }
voidmakecolorwheel(vector<Scalar> &colorwheel) { int RY = 15; int YG = 6; int GC = 4; int CB = 11; int BM = 13; int MR = 6;
int i;
for (i = 0; i < RY; i++) colorwheel.push_back(Scalar(255, 255 * i / RY, 0)); for (i = 0; i < YG; i++) colorwheel.push_back(Scalar(255 - 255 * i / YG, 255, 0)); for (i = 0; i < GC; i++) colorwheel.push_back(Scalar(0, 255, 255 * i / GC)); for (i = 0; i < CB; i++) colorwheel.push_back(Scalar(0, 255 - 255 * i / CB, 255)); for (i = 0; i < BM; i++) colorwheel.push_back(Scalar(255 * i / BM, 0, 255)); for (i = 0; i < MR; i++) colorwheel.push_back(Scalar(255, 0, 255 - 255 * i / MR)); }
voidmotionToColor(Mat flow, Mat &color){ if (color.empty()) color.create(flow.rows, flow.cols, CV_8UC3); staticvector<Scalar> colorwheel; //Scalar r,g,b if (colorwheel.empty()) makecolorwheel(colorwheel); // determine motion range: float maxrad = -1; // Find max flow to normalize fx and fy for (int i = 0; i < flow.rows; ++i){ for (int j = 0; j < flow.cols; ++j){ Vec2f flow_at_point = flow.at<Vec2f>(i, j); float fx = flow_at_point[0]; float fy = flow_at_point[1]; if ((fabs(fx) > UNKNOWN_FLOW_THRESH) || (fabs(fy) > UNKNOWN_FLOW_THRESH)) continue; float rad = sqrt(fx * fx + fy * fy); maxrad = maxrad > rad ? maxrad : rad; } } for (int i = 0; i < flow.rows; ++i){ for (int j = 0; j < flow.cols; ++j){ uchar *data = color.data + color.step[0] * i + color.step[1] * j; Vec2f flow_at_point = flow.at<Vec2f>(i, j); float fx = flow_at_point[0] / maxrad; float fy = flow_at_point[1] / maxrad; if ((fabs(fx) > UNKNOWN_FLOW_THRESH) || (fabs(fy) > UNKNOWN_FLOW_THRESH)){ data[0] = data[1] = data[2] = 0; continue; } float rad = sqrt(fx * fx + fy * fy); float angle = atan2(-fy, -fx) / CV_PI; float fk = (angle + 1.0) / 2.0 * (colorwheel.size() - 1); int k0 = (int)fk; int k1 = (k0 + 1) % colorwheel.size(); float f = fk - k0; for (int b = 0; b < 3; b++){ float col0 = colorwheel[k0][b] / 255.0; float col1 = colorwheel[k1][b] / 255.0; float col = (1 - f) * col0 + f * col1; if (rad <= 1) col = 1 - rad * (1 - col); // increase saturation with radius else col *= .75; // out of range data[2 - b] = (int)(255.0 * col); } } } }
Mat flow; // some faster than mat image container UMat flowUmat, prevgray; for (int i = 0; i < 500; i++) { // loop number depends on you (<= frames) Mat img; Mat original; // capture frame from video file cap >> img; imshow("original", img); /* save original for later */ img.copyTo(original); /* just make current frame gray */ cvtColor(img, img, COLOR_BGR2GRAY); /* not a fisrt frame, do optical flow */ if (prevgray.empty() == false) { // calculate optical flow calcOpticalFlowFarneback(prevgray, img, flowUmat, 0.5, 3, 15, 3, 5, 1.2, 0); // copy Umat container to standard Mat flowUmat.copyTo(flow); /* -------------- visulize flow ----------------*/ Mat motion2color; motionToColor(flow, motion2color); imshow("visualize flow 1", motion2color); Mat blackbg(original.rows, original.cols, CV_8UC3, cv::Scalar(0, 0, 0)); drawLines(flow, original); imshow("optical flow", original); // fill previous image again img.copyTo(prevgray); } else { // first frame, fill previous image img.copyTo(prevgray); } waitKey(1); } }