3.使用树莓派控制摄像头采集视频及运动检测
条件: 树梅派安装opencv和免驱动的摄像头
c源码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> //时间函数头 4 #include "opencv.hpp" 5 6 /** 7 * A program to detect motion in front of an USB camera using OpenCV. 8 **/ 9 10 int main(int argc, char **argv) { 11 int detectThreshold = 19; //运动检测预设值(时间) 12 if (argc >= 2) { //判断参数是否充足判断 13 detectThreshold = atoi(argv[1]); 14 printf("=== Motion detection threshold has been set to: [%d] ===\n", detectThreshold); 15 } 16 17 /* init 摄影机 */ 18 CvCapture* pCapture = cvCreateCameraCapture(0); 19 if (NULL == pCapture) { 20 fprintf(stderr, "Can't initialize webcam!\n"); 21 return 1; 22 } 23 cvSetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_WIDTH, 640); 24 cvSetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_HEIGHT, 480); 25 cvSetCaptureProperty(pCapture, CV_CAP_PROP_BRIGHTNESS, 20); 26 cvSetCaptureProperty(pCapture, CV_CAP_PROP_CONTRAST, 10); 27 28 /* 图像指针 */ 29 IplImage *pFrameA = cvQueryFrame(pCapture); //从摄像头或者文件中抓取并返回一帧 30 IplImage *pFrameB = cvCreateImage(cvSize(pFrameA->width, pFrameA->height), pFrameA->depth, pFrameA->nChannels); //创建图像((矩形框大小),颜色深度,通道) 31 //就是直接把pFrameB这个图像复制给dst,不用给 pFrameDiff 特地开辟内存空间了 32 IplImage *pFrameDiff = cvCloneImage(pFrameB); 33 34 int nDims = 256; 35 float hRangesArr[] = {0, 255}; 36 float* hRanges = hRangesArr; 37 /*直方图,表上数字图像中亮度分布的一种图,标绘了每个像素的亮度数(可以使用直方图对图像进行二值化,通过计算差异图像的直方图,可以知道这两附图有没有差异*/ 38 IplImage *pGrayscaleImage = NULL; 39 CvHistogram *pHist = cvCreateHist(1, &nDims, CV_HIST_ARRAY, &hRanges, 1); 40 float fMaxValue = 0.0; 41 42 time_t ts = 0; //用于记录当前时间戳和防止1次触发多次监测检测 43 while(true) { 44 pFrameA = cvQueryFrame(pCapture); //从摄像头或者文件中抓取并返回一帧 45 if(!pFrameA){ //判断是否成功采集 46 fprintf(stdout,"Can't grab images!\n"); 47 break; 48 } 49 cvAbsDiff(pFrameB,pFrameA,pFrameDiff); //计算两幅图像的差异 50 cvCopy(pFrameA,pFrameB); //复制图像,第一个参数是源与第二目标 51 //实现了8位深的灰度图像 52 pGrayscaleImage = cvCreateImage(cvGetSize(pFrameDiff),IPL_DEPTH_8U,1); 53 //void cvCvtColor( const CvArr* src, CvArr* dst, int code ); 54 //src 输入的 8-bit,16-bit或 32-bit单倍精度浮点数影像。 55 //dst 输出的8-bit, 16-bit或 32-bit单倍精度浮点数影像。 56 //code 色彩空间转换的模式,该code来实现不同类型的颜色空间转换。比如CV_BGR2GRAY表示转换为灰度图,CV_BGR2HSV将图片从RGB空间转换为HSV空间。其中当code选用CV_BGR2GRAY时,dst需要是单通道图片。当code选用CV_BGR2HSV时,对于8位图,需要将RGB值归一化到0-1之间。这样得到HSV图中的H范围才是0-360,S和V的范围是0-1。 57 cvCvtColor(pFrameDiff, pGrayscaleImage, CV_BGR2GRAY); 58 cvCalcHist(&pGrayscaleImage, pHist, 0, 0); 59 60 fMaxValue = 0.0; 61 //找到直方图中最大最小直方块,以及他们的位置,并保存到 fMaxValue 中 62 cvGetMinMaxHistValue(pHist, 0, &fMaxValue, 0, 0); 63 //用于对直方图的比例缩放 64 cvConvertScale(pHist->bins, pHist->bins, (fMaxValue ? (255.0 / fMaxValue) : 0.0), 0); 65 //检查是否有运动状态 66 double dRealtimeVal = cvGetReal1D(pHist->bins, 10); 67 if (dRealtimeVal > detectThreshold) { //触发 68 time_t currentTimestamp = time(NULL); 69 if (currentTimestamp - ts >= 1) { //对时间戳进行判断 70 ts = currentTimestamp; 71 printf("Motion detected @ %s", ctime(¤tTimestamp)); 72 } 73 } 74 cvReleaseImage(&pGrayscaleImage); //释放内存 75 pGrayscaleImage = NULL; 76 77 cvWaitKey(10); //等待n毫秒 78 } 79 //停止捕获图像和释放资源 80 cvReleaseCapture(&pCapture); 81 cvReleaseHist(&pHist); 82 cvReleaseImage(&pFrameA); 83 cvReleaseImage(&pFrameB); 84 cvReleaseImage(&pFrameDiff); 85 86 pCapture = NULL; 87 pHist = NULL; 88 pFrameA = NULL; 89 pFrameB = NULL; 90 pFrameDiff = NULL; 91 92 return 0; 93 }
脚本:
detect-motion-using-opencv.sh
1 #!/bin/bash 2 # A script to invoke a C program to detect motion in front of an USB camera using OpenCV. 3 4 CURRENT_DIR=`dirname "$0"` 5 WORKING_HOME=`cd "$CURRENT_DIR"; pwd` 6 7 SOURCE_FILE=$WORKING_HOME/motion-detection.c 8 BIN_FILE=$WORKING_HOME/motion-detection 9 MOTION_DETECTION_THRESHOLD=100 10 11 # compile the source code if the executable bin not exists 12 if [ ! -f $BIN_FILE ]; then 13 echo "Compiling $SOURCE_FILE ..." 14 g++ -I/usr/include/opencv2/ `pkg-config --cflags opencv --libs opencv` $SOURCE_FILE -o $BIN_FILE 15 if [ $? -ne 0 ]; then 16 echo "Failed to compile $SOURCE_FILE" 17 exit 1 18 fi 19 fi 20 21 # run the program 22 $BIN_FILE $MOTION_DETECTION_THRESHOLD