C代码实践——《Head first C》C语言实验室2
任务要求
入侵者检测器
计算机用摄像头持续监测周围环境,当检测到有物体在移动时就会把当前捕捉到的图像保存为文件。
完成过程
Step1.安装OpenCV
访问OpenCV官网下载适合操作系统的OpenCV,我起初下载的是最新版,但后来了解到最新版删除了不少旧版的C语言接口,就下回了2.x旧版本。
Step2.配置环境变量
将OpenCV的bin目录添加到系统环境变量中,具体操作如下
Step3.配置编译环境
创建工程并准备初步测试代码,在工程文件相应位置(我用vscode就在.vscode文件夹里)大致配置好tasks.json、c_cpp_properties.json,并进行测试
这是我第一次配置,我捯饬了老半天,一边问GPT一边自己瞎试,其实关键就是成功链接到opencv的相应库。
我的tasks.json配置如下:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc.exe 生成活动文件",
"command": "C:/Program Files/mingw64/bin/gcc.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe",
"-ID:/opencv/opencv/build/include",
"-LD:/opencv/opencv/build/x64/vc14/lib",
"-lopencv_core2413",
"-lopencv_imgproc2413",
"-lopencv_highgui2413",
"-lopencv_video2413"
],
"options": {
"cwd": "C:/Program Files/mingw64/bin"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}
我的c_cpp_properties.json配置如下:
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"D:/opencv/opencv/build/include/"
],
"defines": [],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "C:/Program Files/mingw64/bin/gcc.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "${default}"
}
],
"version": 4
}
Step4.编写程序代码
按照任务要求与提示编写程序代码.现在有了GPT,方便很多,不懂的函数,直接让GPT手把手带你写,但这里我也出了不少几次错误,不过问GPT加自己“研究”(瞎捣鼓)也凑活写出来了。(具体代码见文尾)
Step5.测试运行调整
试运行程序并对程序代码进行调整。刚开始运行的时候,我人晃半天都检测不到,然后我就修改参数,改了几次之后也就差不多了。
反思、总结、收获
程序也凑合着能用了,但真要达到目的恐怕远远不够(比如这个程序只能记录最后一个可疑图像,而这个图像往往是thief离开的图像,很难看清thief)。
这个过程也是一波三折,一开始不知道配置环境变量,然后不会配置tasks.json、c_cpp_properties.json,后来程序也老是出错,折腾几天,有点头疼。不过这个过程也的的确确锻炼了自己做工程写程序的能力,积攒了相关的经验
最终程序代码
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv/cv.h>
#include <stdio.h>
int main()
{
CvCapture *capture = cvCaptureFromCAM(0); // 从默认摄像头捕获视频
if (!capture)
{
fprintf(stderr, "错误:无法打开摄像头\n");
return -1;
}
IplImage *frame;
IplImage *prev;
IplImage *next;
IplImage *prevGray;
IplImage *nextGray;
fprintf(stderr, "successly start!\n");
while (1)
{
frame = cvQueryFrame(capture); // 从摄像头捕获一帧图像
if (!frame)
break;
// 加载两帧图像
prev = cvQueryFrame(capture);
next = cvQueryFrame(capture);
// 为灰度图像分配空间
prevGray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
nextGray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
// 将第一帧转换为灰度
cvCvtColor(frame, prevGray, CV_BGR2GRAY);
cvCvtColor(frame, nextGray, CV_BGR2GRAY);
// 创建光流图像
CvSize img_sz = cvGetSize(prevGray);
CvMat *flow = cvCreateMat(img_sz.height, img_sz.width, CV_32FC2);
// 计算光流
cvCalcOpticalFlowFarneback(prevGray, nextGray, flow, 0.5, 5, 31, 3, 7, 1.5, 0);
for (int y = 0; y < flow->rows; y++)
{
float *flow_ptr = (float *)(flow->data.ptr + flow->step * y);
for (int x = 0; x < flow->cols; x++)
{
float x_flow = flow_ptr[x * 2];
float y_flow = flow_ptr[x * 2 + 1];
// 计算向量的大小(magnitude)
float magnitude = sqrt(x_flow * x_flow + y_flow * y_flow);
if (2 * x + 1 >= flow->cols)
break;
// 检测显著运动
if (magnitude > 0.5)
{
cvSaveImage("thief.jpg", next, 0);
// 在这里处理显著运动的逻辑
}
}
}
// 释放图像和光流数据
if (prevGray != NULL)
{
cvReleaseImage(&prevGray);
prevGray = NULL; // 将指针设为NULL,防止野指针
}
if (nextGray != NULL)
{
cvReleaseImage(&nextGray);
nextGray = NULL; // 同上
}
if (prev != NULL)
{
cvReleaseImage(&prevGray);
prevGray = NULL; // 将指针设为NULL,防止野指针
}
if (next != NULL)
{
cvReleaseImage(&nextGray);
nextGray = NULL; // 同上
}
if (flow != NULL)
{
cvReleaseMat(&flow);
flow = NULL; // 同上
}
}
cvReleaseCapture(&capture); // 释放IplImage资源
return 0;
}