由于视频是一帧帧刷新的,常见的绘图方法只适用于不变的Mat上,而视频播放下一帧之后上一帧所绘制的图像则随着上一帧被刷掉了,而MFC则是创建一块DC,在DC内画所以原理不同。为了实现在视频和摄像头画面中进行绘图,则需要将绘图点保存在容器中,并在每帧播放的时候都要进行绘图,才能实现连贯的绘图。而OPENCV利用Circle进行画曲线画出来的线是离散的很容易断,与MFC效果又差太远,故想出了利用Polylines和Circle同时绘画,重合出一条连贯的实线,但因此这种方法性能很差,不知有没有其他实现曲线的办法,如果有可以评论区教教我嘻嘻
#include<iostream>
#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <vector>
using namespace std;
using namespace cv;
bool g_bDrawing = false;
Point g_nCurrPoint;
Point g_nEndPoint;
vector<pair<Point, Point>> vecDrawPoint;
pair<Point, Point> tempPoint;
vector<Point> vecCircle;
vector<Point> vecpoly;
vector<vector<Point>> vecCirLine;
void onMouse(int event, int x, int y, int flag, void* param)
{
Mat& img = *(cv::Mat*)param;
switch (event)
{
//移动鼠标的时候
case CV_EVENT_MOUSEMOVE:
{
if (g_bDrawing == true)
{
g_nEndPoint = Point(x, y);
tempPoint.first = g_nCurrPoint;
tempPoint.second = g_nEndPoint;
vecCircle.push_back(g_nEndPoint);
vecpoly.push_back(g_nEndPoint);
}
}
break;
//点击鼠标左键时
case CV_EVENT_LBUTTONDOWN:
{
g_bDrawing = true;
g_nCurrPoint = Point(x, y);
}
break;
//松开鼠标左键时
case CV_EVENT_LBUTTONUP:
{
g_bDrawing = false;
g_nEndPoint = Point(x, y);
if (g_nEndPoint != g_nCurrPoint)
{
pair<Point, Point> linePoint(g_nCurrPoint, g_nEndPoint);
vecDrawPoint.push_back(linePoint);
}
vecpoly.clear();
}
break;
}
}
void DrawRectangle(Mat matFrame)
{
rectangle(matFrame, tempPoint.first, tempPoint.second, Scalar(255, 255, 0), 2);
if (!vecDrawPoint.empty())
{
for (int i = 0; i < vecDrawPoint.size(); i++)
{
rectangle(matFrame, vecDrawPoint[i].first, vecDrawPoint[i].second, Scalar(255, 255, 0), 2);
}
}
}
void DrawLine(Mat matFrame)
{
line(matFrame, tempPoint.first, tempPoint.second, Scalar(255, 255, 0), 1, CV_AA);
if (!vecDrawPoint.empty())
{
for (int i = 0; i < vecDrawPoint.size(); i++)
{
line(matFrame, vecDrawPoint[i].first, vecDrawPoint[i].second, Scalar(255, 255, 0), 1, CV_AA);
}
}
}
void DrawCir(Mat matFrame)
{
for (int i = 0; i < vecCircle.size(); i++)
{
circle(matFrame, vecCircle[i], 0, Scalar(255, 255, 0), 2, CV_AA);
}
if (!vecCircle.empty())
{
vecCirLine.push_back(vecpoly);
for (int i = 0; i < vecCirLine.size(); i++)
{
polylines(matFrame, vecCirLine[i], false, Scalar(255, 255, 0), 2);
}
}
}
int main()
{
int nDrawType = 2;//设置绘图类型 1:直线 2:矩形 3:曲线
string strPath= "E:/test.avi";
VideoCapture Vcap;
VideoWriter writer(strPath, 1, Vcap.get(CAP_PROP_FPS), cv::Size(Vcap.get(CAP_PROP_FRAME_WIDTH),
Vcap.get(CAP_PROP_FRAME_HEIGHT)),true);
Vcap.open(0/*"视频文件路径"*/);//为0时获取第一个摄像头设备画面,为路径时则打开路径指向的视频文件
if (!Vcap.isOpened())
{
return 0;
}
Mat matFrame;
namedWindow("video", 0);
setMouseCallback("video", onMouse, (void*)&matFrame);
while (1)
{
Vcap >> matFrame;
//Canny(matFrame, matCFrame, 20, 100,3);//边缘检测
if (matFrame.empty())
{
break;
}
switch (nDrawType)
{
case 1:
DrawLine(matFrame);//画直线
break;
case 2:
DrawRectangle(matFrame);//画矩形
break;
case 3:
DrawCir(matFrame);//画曲线
break;
default:
break;
}
writer.write(matFrame);
imshow("video", matFrame);
if (waitKey(60) > 0)
{
break;
}
}
Vcap.release();
destroyAllWindows();
return 0;
}