由于实验室里面需要做CDVA的标准,CDVA(compact descriptor for video analysis),主要是基于CDVS中的紧凑视觉描述子来做视频分析,之前是紧凑视觉描述子主要应用在图像检索领域。需要制作新的数据集,对视频帧进行标注,所以根据网上一个博主的标注工具进行了一定的修改,实现的功能是在每一帧中将需要标注的区域用鼠标选取4个点,顺序是顺时针。因为四边形的范围更广,之前的一些人直接标注了矩形,但是在一些仿射变换中,往往矩形的定位效果不好,矩形定位应该比较适合于人脸定位和行人定位之中。
这些代码都是基于openCV的,因此在工程配置的时候需要天机opencv的库路径和头文件路径。
这里简单的介绍一下这个工具的用法
在写入的txt文件中,一行代表一帧中的数据,第一个数为帧数,后4个数,分别是画矩形时依次点入的4个坐标值。
你可以根据自己的需求,修改这份代码,希望对大家能有所帮助。
/******************************************************************** created: 2015/04/18 created: 18:4:2015 17:24 filename: D:\WorkSpace\VS_Projects\VideoLabel\VideoLabel_Quadrilateral\video_label_quadrilateral.cpp file path: D:\WorkSpace\VS_Projects\VideoLabel\VideoLabel_Quadrilateral file base: video_label_quadrilateral file ext: cpp author: Yihang Lou purpose: draw the quadrilateral labels in the frame captured from video *********************************************************************/
#include "opencv2/opencv.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
using namespace cv;
// Global variables
Mat img_original, img_drawing;
Point quad [4];
//the value of pointNum is between 0~4
static int pointNum = 0;
/************************************************* // Method: help // Description: describe the usage // Author: Yihang Lou // Date: 2015/04/18 // Returns: void // History: *************************************************/
static void help() {
cout << "This program designed for labeling video \n"
"Only if you press the 'n' the present quadrilateral data will be written into txt file\n";
cout << "Hot keys: \n"
"\tESC - quit the program\n"
"\tn - next frame of the video\n"
"\tz - undo the last label point \n"
"\tc - clear all the labels\n"
<< endl;
}
/************************************************* // Method: drawQuadri // Description: // Author: Yihang Lou // Date: 2015/04/18 // Returns: void // Parameter: quad the point of Point array // History: *************************************************/
static void drawQuadri (Point * quad) {
for(int i = 0; i < 4; i++)
{
line(img_drawing,quad[i],quad[(i+1)%4],Scalar(0,255,0),1,8,0);
}
}
/************************************************* // Method: onMouse // Description: do the actions after onMouse event is called // Author: Yihang Lou // Date: 2015/04/18 // Returns: void // Parameter: event // Parameter: x Mouse's coordinate // Parameter: y // History: *************************************************/
static void onMouse(int event, int x, int y, int, void*) {
switch (event)
{
case CV_EVENT_LBUTTONDOWN:
quad[pointNum%4].x = x;
quad[pointNum%4].y = y;
cout<<"x = "<<x<<" y = "<<y<<endl;
pointNum++;
break;
case CV_EVENT_LBUTTONUP:
//finish drawing the rect (use color green for finish)
circle(img_drawing,cvPoint(x,y),1,Scalar(0, 255, 0),1,8,0);
if(pointNum == 4)
{
pointNum = 0;
cout<<"draw quadri line"<<endl;
drawQuadri(quad);
}
break;
}
imshow("Video", img_drawing);
return;
}
/************************************************* // Method: isempty // Description: check the quad is empty // Author: Yihang Lou // Date: 2015/04/18 // Returns: int // Parameter: quad // History: *************************************************/
int isempty(Point * quad) {
for (int i = 0 ; i < 4; i++)
{
if (quad[i].x !=0 || quad[i].y !=0 )
{
return 0;
}
}
return 1;
}
int main(){
namedWindow("Video");
ofstream outfile("1.txt");
help();
VideoCapture capture("1.avi");
capture >> img_original;
img_original.copyTo(img_drawing);
imshow("Video", img_original);
setMouseCallback("Video", onMouse, 0);
int frame_counter = 0;
while (1){
int c = waitKey(0);
if ((c & 255) == 27)
{
cout << "Exiting ...\n";
break;
}
switch ((char)c)
{
case 'n':
//read the next frame
++frame_counter;
capture >> img_original;
if (img_original.empty()){
cout << "\nVideo Finished!" << endl;
return 0;
}
img_original.copyTo(img_drawing);
if (!isempty(quad))
{
drawQuadri(quad);
outfile << frame_counter << " " << quad[0].x << " "<< quad[0].y << " "
<< quad[1].x << " "<< quad[1].y << " "
<< quad[2].x << " "<< quad[2].y << " "
<< quad[3].x << " "<< quad[3].y << " "<<endl;
}
break;
case 'z':
//undo the latest labeling point
if(pointNum == 0)
{
cout<<"if you want to clear the existent quad please press 'c'"<<endl;
break;
}
pointNum--;
quad[pointNum].x=0;
quad[pointNum].y=0;
img_original.copyTo(img_drawing);
for(int i = 0 ; i < pointNum; i++)
{
circle(img_drawing,quad[i],1,Scalar(0, 255, 0),1,8,0);
}
break;
case 'c':
//clear quad array
memset(quad,0,4*sizeof(Point));
img_original.copyTo(img_drawing);
}
imshow("Video", img_drawing);
}
return 0;
}