运行环境
Visual Studio 2017+opencv 3.4
跟着这位大佬思路安装一路绿灯:https://blog.csdn.net/qq_41175905/article/details/80560429
功能和思路
能识别出摄像头拍到的任何移动物体,眨眼都可以捕捉到!
思路:
- 读取图片
- 图片转换成二维数组
- 判断30ms前后延迟前后图片每个像素是否有差异(阈值在20之间)
- 把大于阈值的用不同背景色标出
- 显示图片
Mat类转换成二维数组
我们在摄像头获取到的图片都是GBR类型的,为什么说是GBR呢,因为在Opencv里面,三个通道的排序是B、G、R
对于单通道图像:
Mat对象.at<uchar>(x,y);
x,y是图像上的坐标,返回一个uchar值
对于三通道图像(BGR图):
Mat对象.at<Vec3b>(x,y);
x,y是图像上的坐标,返回一个长度为3的uchar数组,分别代表BGR通道的像素值,Vec3b是一种类型,有时也会使用Vec3f,区别是b:uchar类型,f:float类型,我们当成int型使用
附一张API
- 我们读取到Mat类型的图片,为了方便使用,把它转换为单通道的图片,像素改成(B+G+R)/3
- 为什么说单通道方便呢,因为单通道可以直接整形,也可以用(b,g,r)给三通道图片赋值~
- 看代码比较容易理解
void getimage(Mat m, int flag) {
Size imgsize = m.size();
for (int i = 0; i < m.rows; i ++) {
for (int j = 0; j < m.cols; j ++) {
//得出三个不同的像素值
Vec3b bgr = m.at<Vec3b>(i, j);
int b = bgr[0];
int g = bgr[1];
int r = bgr[2];
//img1 img2分别是不同时间下的图片(30ms)
if (flag == 1) {
img1[i][j] = (b + g + r) / 3;
}
else
{
img2[i][j]= (b + g + r) / 3;
}
}
}
}
判断比较
- 首先要初始化图片背景
- 再用两个数组的各个值相比较(像素比较),给定一个阈值偏差小于该值认为没有移动,大于就是移动了
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
if(abs(img1[i][j]-img2[i][j])>20){
newImage.at<uchar>(i, j) = 0;
// drawFilledCircle(newImage, Point(i, j));
}
}
}
code
有个画圆的函数,画出来有偏差,而且影响美观,就不用了,不过这个功能在其他需要画图的地方还是可以的。
#include<iostream>
#include<opencv/cv.h>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int img1[480][640], img2[480][640];
void getimage(Mat m, int flag) {
Size imgsize = m.size();
for (int i = 0; i < m.rows; i ++) {
for (int j = 0; j < m.cols; j ++) {
//得出三个不同的像素值
Vec3b bgr = m.at<Vec3b>(i, j);
int b = bgr[0];
int g = bgr[1];
int r = bgr[2];
//img1 img2分别是不同时间下的图片(30ms)
if (flag == 1) {
img1[i][j] = (b + g + r) / 3;
}
else
{
img2[i][j]= (b + g + r) / 3;
}
}
}
}
/*画实心圆*/
void drawFilledCircle(cv::Mat img, cv::Point center) {
int thickness = 1;
int lineType = 8;
cv::circle(img,
center, //圆心定义
2, //圆的半径
Scalar(rand()%255, rand()%255, rand()%255),//随机颜色
thickness,//线粗
lineType);
}
int main() {
VideoCapture capture(0);
Mat frame;
int count = 1;
while (true) {
capture >> frame;
Size imgsize = frame.size();
count = -count;
Mat newImage = Mat(imgsize, CV_8UC1);
//cout << frame.rows << " " << frame.cols;
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
newImage.at<uchar>(i, j) = 255;
}
}
getimage(frame, count);
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
if(abs(img1[i][j]-img2[i][j])>20){
newImage.at<uchar>(i, j) = 0;
// drawFilledCircle(newImage, Point(i, j));
}
}
}
if (!frame.empty()) {
imshow("NewImage", newImage);
}
if (waitKey(30) == 27)
break;
}
}
我同学用=用visual studio做CV都很卡!!