颜色范围查询表:
代码:
void Quick_Demo::object_follow_byscalar_demo()
{
VideoCapture cap(0);
Mat frame,mask,output;
char ch;
float mini_index = 0.7;
while (true) {
//打开错误反馈
if (!cap.isOpened())
break;
cap >> frame;
ch = waitKey(100);
if (ch == 27)
break;
//尺寸灰度转换,翻转
resize(frame, frame, Size(), mini_index, mini_index,INTER_AREA);
cvtColor(frame, frame, COLOR_BGR2HSV);
flip(frame, frame, 1);
//设置颜色上下限,查表得到红色的上下限
Scalar low_bound = Scalar(0, 0, 221);
Scalar up_bound = Scalar(180, 30, 255);
//获取mask掩膜
inRange(frame, low_bound, up_bound, mask);
bitwise_and(frame, frame, output, mask);
//中值模糊
medianBlur(output, output, 5);
imshow("input", frame);
imshow("object",output);
}
cap.release();
destroyAllWindows();
}
涉及算法:meanshift,CAMshift
meanshift:
根据选定的ROI区域的颜色直方图选定若干点,然后计算空间点图心。如果在过程中图心始终位于该ROI的中心,则对象没有移动,若图心改变,则对象朝图心改变的方向移动。但它不会允许改变边界框大小(即只允许图像对象的平动,不允许前后运动)。
CAMshift:
在meanshift的基础上可以自适应边界框大小,还可以追踪对象的方向。
包括鼠标点击,抬起事件。
1、预先定义:
鼠标事件布尔值,起始点,终止点,捕获图像矩阵相关Mat,选取矩形框,如:
Mat frame, gray; //源图像和源灰度图像
Mat framecopy; //用于拷贝出的源图像
Mat framerect, framerecthsv; //矩形选取后的图像
Rect rect; //鼠标选取的矩形
//鼠标控制
bool firstleftbutton = false;
bool leftButtonDownFlag = false; //左键单击后视频暂停播放的标志位
Point rectstartPoint; //矩形框起点
Point rectstopPoint; //矩形框终点//直方图
int histSize = 200;
float histR[] = { 0,255 };
const float* histRange = histR;
int channels[] = { 0,1 };
Mat dstHist;
2、点击事件
更新鼠标事件布尔值为true、起始点,终止点坐标。
leftButtonDownFlag = true; //更新按下标志位
rectstartPoint = Point(x, y); //设置矩形的开始点
rectstopPoint = rectstartPoint; //刚按下时结束点和开始点一样
3、抬起事件
更新鼠标事件布尔值为false、捕获矩形框、framerect,在对应框内计算对应直方图、归一化显示直方图结果。
leftButtonDownFlag = false;//按下鼠标标志位复位
rect = Rect(rectstartPoint, rectstopPoint);//设置选中后的矩形
framerect = frame(rect); //通过矩形获取到选取后的图像
imshow("selectimg", framerect);//显示出来选择后的图像
cvtColor(framerect, framerecthsv, COLOR_BGR2HSV);
//直方图计算
calcHist(&framerecthsv, 2, channels, Mat(), dstHist, 1, &histSize, &histRange, true, false);
//归一化显示
normalize(dstHist, dstHist, 0, 255, NORM_MINMAX);
4、鼠标移动事件
更新源图像,防止矩形框重叠显示, 更新矩形框点,绘制矩形框,显示框选图像。
framecopy = frame.clone(); //复制源图像
rectstopPoint = Point(x, y); //设置矩形的结束点
if (rectstartPoint != rectstopPoint)
{
//当矩形的开始点和结束点不同后在复制的图像上绘制矩形
rectangle(framecopy, rectstartPoint, rectstopPoint,
Scalar(255, 255, 255));
}
imshow("srcvideo", framecopy);
代码:
Mat frame, gray; //源图像和源灰度图像
Mat framecopy; //用于拷贝出的源图像
Mat framerect, framerecthsv; //矩形选取后的图像
Rect rect; //鼠标选取的矩形
//直方图
int histSize = 200;
float histR[] = { 0,255 };
const float* histRange = histR;
int channels[] = { 0,1 };
Mat dstHist;
//保存目标轨迹
std::vector pt;
//鼠标控制
bool firstleftbutton = false;
bool leftButtonDownFlag = false; //左键单击后视频暂停播放的标志位
Point rectstartPoint; //矩形框起点
Point rectstopPoint; //矩形框终点
void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数
void onMouse(int event, int x, int y, int flags, void* ustc)
{
//鼠标左键按下
if (event == EVENT_LBUTTONDOWN)
{
leftButtonDownFlag = true; //更新按下标志位
rectstartPoint = Point(x, y); //设置矩形的开始点
rectstopPoint = rectstartPoint; //刚按下时结束点和开始点一样
}
//当鼠标按下并且开始移动时
else if (event == EVENT_MOUSEMOVE && leftButtonDownFlag)
{
framecopy = frame.clone(); //复制源图像
rectstopPoint = Point(x, y); //设置矩形的结束点
if (rectstartPoint != rectstopPoint)
{
//当矩形的开始点和结束点不同后在复制的图像上绘制矩形
rectangle(framecopy, rectstartPoint, rectstopPoint,
Scalar(255, 255, 255));
}
imshow("srcvideo", framecopy);
}
//当鼠标抬起时
else if (event == EVENT_LBUTTONUP)
{
leftButtonDownFlag = false;//按下鼠标标志位复位
rect = Rect(rectstartPoint, rectstopPoint);//设置选中后的矩形
framerect = frame(rect); //通过矩形获取到选取后的图像
imshow("selectimg", framerect);//显示出来选择后的图像
cvtColor(framerect, framerecthsv, COLOR_BGR2HSV);
//直方图计算
calcHist(&framerecthsv, 2, channels, Mat(), dstHist, 1, &histSize, &histRange, true, false);
//归一化显示
normalize(dstHist, dstHist, 0, 255, NORM_MINMAX);
}
}
void Quick_Demo::object_follow_demo()
{
VideoCapture cap(0);
namedWindow("srcvideo", WINDOW_FREERATIO);
//设置图像中鼠标事件
setMouseCallback("srcvideo", onMouse, 0);
bool first = false;
while (true)
{
char ch = waitKey(50);
//当鼠标左键没有按下时
if (!leftButtonDownFlag)
{
cap >> frame;
}
//图像为空或Esc键按下退出播放
if (ch == 27)
break;
//如果已经截取了图像进行处理
if (rectstartPoint != rectstopPoint && !leftButtonDownFlag)
{
Mat imageHSV;
Mat calcBackImage;
cvtColor(frame, imageHSV, COLOR_BGR2HSV);
//反向投影
calcBackProject(&imageHSV, 2, channels,
dstHist, calcBackImage, &histRange);
TermCriteria criteria(TermCriteria::MAX_ITER +
TermCriteria::EPS, 10, 1);
CamShift(calcBackImage, rect, criteria);
//更新模板
Mat imageROI = imageHSV(rect);
framerecthsv = imageHSV(rect);
calcHist(&imageROI, 2, channels, Mat(),
dstHist, 1, &histSize, &histRange);
normalize(dstHist, dstHist, 0.0, 1.0, NORM_MINMAX); //归一化
rectangle(frame, rect, Scalar(255, 0, 0), 3); //目标绘制
pt.push_back(Point(rect.x + rect.width / 2,
rect.y + rect.height / 2));
for (int i = 0; i < pt.size() - 1; i++)
{
line(frame, pt[i], pt[i + 1], Scalar(0, 255, 0), 2.5);
}
}
imshow("srcvideo", frame);
}
cap.release();
waitKey(0);
destroyAllWindows();
}
参考:(33条消息) C++ OpenCV视频操作之CamShift跟踪算法_Vaccae的博客-CSDN博客