#include "cxcore.h"
#include "cv.h"
#include "highgui.h"
# include <iostream>
#include <math.h>
# define NULL 0
const int winHeight = 480;
const int winWidth = 640;
static int nFrmNum = 0;
struct objectList
{
int x;
int y;
struct objectList *next;
};
struct movingObject
{
int area;
int label;
int x;
int y;
CvPoint points[2]; //矩形框的两个对脚点
struct objectList *head;
struct movingObject *next;
};
void bin_img_or(IplImage *image, IplImage *image1, IplImage *image2);
void bg_diff(IplImage *pFrame, IplImage *pBkImg, IplImage *pFrImg, CvMat *pFrameMat, CvMat *pBkMat, CvMat *pFrMat);
void computeObject(CvMat* foreImageMat, int width, int height, CvMat* labeledMat, movingObject* head);
int cal_dist(int x1, int y1, int x2, int y2);
void release_obj_link(movingObject *link);
void draw_line(IplImage *image, objectList *t);
static int label_num = 0;
int main()
{
int tmp_x, tmp_label, dist;
int cover_flag = 0;
CvMat* pFrameMat = NULL;
CvMat* pFrMat = NULL;
CvMat* pBkMat = NULL;
IplImage *res = 0; //帧差视频
IplImage *res0 = 0;
IplImage *image = 0; //原始帧
IplImage *image_pass = 0;
IplImage *pBkImg = 0; //背景图像
IplImage *pFrImg = 0; //背景差分视频
IplImage *pFrame = 0;
CvCapture *capture = NULL;
CvMat* LabeledMat = NULL;
movingObject *p_obj = NULL;
const CvMat* prediction = NULL;
CvPoint predict_pt;
CvFont font1, font2;
cvInitFont(&font1, CV_FONT_HERSHEY_TRIPLEX, 1, 1);
cvInitFont(&font2, CV_FONT_HERSHEY_COMPLEX, 0.5, 0.5);
/* CvFont font;
cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX ,1,1);*/
capture = cvCaptureFromFile("D:/picture/cd2.mp4");
IplImage *frame = 0;
frame = cvQueryFrame(capture);
int image_width = (int)frame->width; //得到图像的宽度和高度
int image_height = (int)frame->height;
image = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3); //创建图像首地址并分配存储空间,3通道
image_pass = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
res = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1); //灰度图像
res0 = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
pBkImg = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);
pFrImg = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);
pFrame = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);
//图像对应的矩阵都是一维的
pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
LabeledMat = cvCreateMat(image_height, image_width, CV_32FC1);
movingObject *curr_head = new movingObject();
movingObject *prev_head = new movingObject();
cvCopy(frame, image_pass, NULL);
while (1)
{
image = cvQueryFrame(capture);
if (image == NULL)
{
break;
}
cvShowImage("原始", image);
cvSmooth(image, image, CV_GAUSSIAN, 3, 0, 0, 0);
cvAbsDiff(image, image_pass, res0); //计算两帧图像差的绝对值
cvCvtColor(res0, res, CV_RGB2GRAY); //转换为灰度图像
//cvThreshold(res, res, 50, 255, CV_THRESH_BINARY);
cvAdaptiveThreshold(res, res, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, 5, 5); //二值化
cvShowImage("帧差视频", res);
cvShowImage("背景图像", pBkImg);
bg_diff(image, pBkImg, pFrImg, pFrameMat, pBkMat, pFrMat);
cvShowImage("背景差分视频", pFrImg);
cvZero(pFrame);
bin_img_or(pFrame, res, pFrImg);
cvDilate(pFrame, pFrame, 0, 1);
cvConvert(pFrame, pFrMat);
cvCopy(image, image_pass, NULL);
cvShowImage("或", pFrame);
if (nFrmNum > 1)
{
computeObject(pFrMat, image_width, image_height, LabeledMat, curr_head);
p_obj = curr_head->next;
while (p_obj != NULL)
{
cvRectangle(image, cvPoint(p_obj->x - 1, p_obj->y - 1), cvPoint(p_obj->x + 1, p_obj->y + 1), cvScalar(0, 0, 255), 4, 8, 0); //画出目标的质心
p_obj = p_obj->next;
}
if (nFrmNum == 3)
{
computeObject(pFrMat, image_width, image_height, LabeledMat, prev_head);
}
if (nFrmNum > 3)
{
movingObject *q = NULL, *p = NULL;
q = curr_head->next;
while (q)
{
for (p = prev_head->next; p; p = p->next)
{
dist = cal_dist(p->x, p->y, q->x, q->y);
if (dist <= 25)
{
break;
}
}
if (p == NULL)
{
//生成新标签
q->label = ++label_num;
}
q = q->next;
}
for (q = curr_head->next; q; q = q->next)
{
for (p = prev_head->next; p; p = p->next)
{
dist = cal_dist(p->x, p->y, q->x, q->y);
printf("dist is : %d\n", dist);
if (dist <= 15)
{
q->label = p->label;
q->head->next = p->head;
p->head = NULL;
}
}
draw_line(image, q->head);
cvRectangle(image, q->points[0], q->points[1], cvScalar(0, 255, 0));
char buf[10];
sprintf_s(buf, 10, "%d", q->label);
cvPutText(image, buf, cvPoint(q->points[0].x, q->points[0].y + 20), &font1, CV_RGB(255, 255, 0));
}
printf("\n");
release_obj_link(prev_head->next);
prev_head->next = curr_head->next;
curr_head->next = NULL;
}
}
char FrmNum[30];
sprintf_s(FrmNum, 30, "Frame No: %d", nFrmNum);
cvPutText(image, FrmNum, cvPoint(1, 25), &font2, CV_RGB(0, 0, 255));
cvShowImage("video", image);
int inter = cvWaitKey(16);
if (inter == 27)
{
break;
}
if (inter == 32)
{
if (cvWaitKey(1500000) == 32)
{
}
}
}
cvReleaseImage(&res);
cvReleaseImage(&res0);
cvReleaseImage(&image_pass);
cvReleaseCapture(&capture);
return 0;
}
void draw_line(IplImage *image, objectList *t)
{
objectList *t1 = t;
while (t1 != NULL) //描述目标运动的轨迹
{
if (t1->next != NULL)
{
cvLine(image, cvPoint(t1->x, t1->y), cvPoint(t1->next->x, t1->next->y), cvScalar(255, 0, 255), 2, 8, 0);
}
t1 = t1->next;
}
}
void release_obj_link(movingObject *link)
{
movingObject *p = link, *q = NULL;
objectList *t1 = NULL, *t2 = NULL;
while (p != NULL)
{
q = p;
p = p->next;
t1 = q->head;
q->head = NULL;
while (t1 != NULL)
{
t2 = t1;
t1 = t1->next;
delete t2;
}
delete q;
}
}
int cal_dist(int x1, int y1, int x2, int y2)
{
int distance;
double res;
res = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
distance = (int)(sqrt(res));
return distance;
}
void bin_img_or(IplImage *image, IplImage *image1, IplImage *image2)
{
int i, j;
int width = image->width;
int height = image->height;
unsigned char data1, data2, data;
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
data1 = (unsigned char)image1->imageData[i * width + j];
data2 = (unsigned char)image2->imageData[i * width + j];
if (data1 == 255 || data2 == 255)
{
data = 255;
image->imageData[i * width + j] = (char)data;
}
}
}
void bg_diff(IplImage *pFrame, IplImage *pBkImg, IplImage *pFrImg, CvMat *pFrameMat, CvMat *pBkMat, CvMat *pFrMat)
{
nFrmNum++;
if (nFrmNum == 1)
{
//将彩色图像转化为灰度图像
cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
//将灰度图像存入矩阵,灰度图像是单通道的
cvConvert(pFrImg, pFrameMat);
cvConvert(pFrImg, pFrMat);
cvConvert(pBkImg, pBkMat);
}
else
{
cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
cvConvert(pFrImg, pFrameMat);
//高斯滤波
cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0, 0);
//当前帧减去背景图像并取绝对值
cvAbsDiff(pFrameMat, pBkMat, pFrMat);
//二值化前景图像
cvThreshold(pFrMat, pFrImg, 30, 255.0, CV_THRESH_BINARY);
//滑动平均更新背景(求平均)
cvRunningAvg(pFrameMat, pBkMat, 0.01, 0);
//将背景矩阵转化为图像格式,用以显示
cvConvert(pBkMat, pBkImg);
}
}