当前位置: 首页 > news >正文

OPENCV C++(十一)

鼠标响应函数


//鼠标响应函数
void on_mouse(int EVENT, int x, int y, int flags, void* userdata)
{Mat hh;hh = *(Mat*)userdata;switch (EVENT){case EVENT_LBUTTONDOWN:{vP.x = x;vP.y = y;drawMarker(hh, vP, Scalar(255, 255, 255));//circle(hh, vP, 4, cvScalar(255, 255, 255), -1);imshow(wName, hh);return;}break;}}

 drawMarker(hh, vP, Scalar(255, 255, 255));

这个是画一个十字符号 标记一个点

绘制直方图和以前篇幅一样

//绘制直方图
int drawHist(cv::Mat& histMat, float* srcHist, int bin_width, int bin_heght)
{histMat.create(bin_heght, 256 * bin_width, CV_8UC3);histMat = Scalar(255, 255, 255);float maxVal = *std::max_element(srcHist, srcHist + 256);for (int i = 0; i < 256; i++) {Rect binRect;binRect.x = i * bin_width;float height_i = (float)bin_heght * srcHist[i] / maxVal;binRect.height = (int)height_i;binRect.y = bin_heght - binRect.height;binRect.width = bin_width;rectangle(histMat, binRect, CV_RGB(255, 0, 0), -1);}return 0;
}

 统计视频一个点不受大影响的时候直方图是高斯分布的(灰度)

int index = grayMat.at<uchar>(vP.y, vP.x);

 选取刚才选中的点

histgram[index]++;

在对应的直方图加1

		drawHist(histMat, histgram, bin_width, bin_heght);drawMarker(frame, vP, Scalar(255, 255, 255));

这里还要画一个drawmaker因为第二遍就不会调用了

vp要是全局变量

完整代码:
 

int main() {// 验证某一背景像素值呈高斯分布VideoCapture cap(0);int cnt = 0;float histgram[256] = { 0 };Mat histMat;int bin_width = 3;int bin_heght = 100;while (1){Mat frame;Mat grayMat;cap >> frame;if (cnt == 0){Mat selectMat;frame.copyTo(selectMat);imshow(wName, selectMat);setMouseCallback(wName, on_mouse, &selectMat);waitKey(0);destroyAllWindows();}cvtColor(frame, grayMat, COLOR_BGR2GRAY);int index = grayMat.at<uchar>(vP.y, vP.x);histgram[index]++;drawHist(histMat, histgram, bin_width, bin_heght);drawMarker(frame, vP, Scalar(255, 255, 255));imshow("frame", frame);imshow("histMat", histMat);if (waitKey(30) == 27) {destroyAllWindows();break;}cnt++;}
return 0;
}

当然还有一些变量需要自己设置全局变量


直接拿原图和新图直接做差分

	VideoCapture cap(0);int cnt = 0;Mat frame;while (1) {cap>> frame;cvtColor(frame, frame, COLOR_BGR2GRAY);if (cnt == 0) {//第一帧,获得背景图像frame.copyTo(bgMat);}else {//第二帧开始背景差分//背景图像和当前图像相减absdiff(frame, bgMat, subMat);//差分结果二值化namedWindow("Result", WINDOW_AUTOSIZE);//滑动条创建cv::createTrackbar("threshold", "Result", &sub_threshold, 255, threshold_track);threshold_track(0, 0);imshow("frame", frame);}if (waitKey(30) == 27) {destroyAllWindows();break;}cnt++;}

 其中

absdiff(frame, bgMat, subMat);

如果摄像机是固定的,那么我们可以认为场景(背景)大多数情况下是不变的,而只有前景(被跟踪的目标)会运动,这样就可以建立背景模型。通过比较当前帧和背景模型,就能轻松地跟踪目标运动情况了。这里,最容易想到的比较方式就是当前帧减去背景模型了

将差分的图像二值化 这里创建了滑动条 bar

void threshold_track(int, void*)//这里就是定义的一个回调函数,里面是canny相关的操作
{threshold(subMat, bny_subMat, sub_threshold, 255, CV_THRESH_BINARY);imshow("Result", bny_subMat);
}


运用了高斯差分 因为本身图像的点都符合高斯分布,收光照等等影响,而这些都不能被考虑进移动物

    int nBg = 200;	cap >> frame;cvtColor(frame, frame, COLOR_BGR2GRAY);if (cnt <= nBg) {srcMats.push_back(frame);if (cnt == 0) {std::cout << "--- reading frame --- " << std::endl;}else {std::cout << "-";if (cnt % 50 == 0)std::cout << std::endl;}}

 这里是前200张帧是为了获取高斯分布

计算图像的平均值和方差(灰度)

int calcGaussianBackground(std::vector<cv::Mat> srcMats, cv::Mat& meanMat, cv::Mat& varMat)
{int rows = srcMats[0].rows;int cols = srcMats[0].cols;for (int h = 0; h < rows; h++){for (int w = 0; w < cols; w++){int sum = 0;float var = 0;//求均值for (int i = 0; i < srcMats.size(); i++) {sum += srcMats[i].at<uchar>(h, w);}meanMat.at<uchar>(h, w) = (uchar)(sum / srcMats.size());//求方差for (int i = 0; i < srcMats.size(); i++) {var += (float)pow((srcMats[i].at<uchar>(h, w) - meanMat.at<uchar>(h, w)), 2);}varMat.at<float>(h, w) = var / srcMats.size();}}return 0;
}

利用平均值和方差来判断是否是入侵背景的前景


int gaussianThreshold(cv::Mat srcMat, cv::Mat meanMat, cv::Mat varMat, float weight, cv::Mat& dstMat)
{int rows = srcMat.rows;int cols = srcMat.cols;for (int h = 0; h < rows; h++){for (int w = 0; w < cols; w++){int dif = abs(srcMat.at<uchar>(h, w) - meanMat.at<uchar>(h, w));int th = (int)(weight * varMat.at<float>(h, w));if (dif > th) {dstMat.at<uchar>(h, w) = 255;}else {dstMat.at<uchar>(h, w) = 0;}}}return 0;
}

这里的weight是权重,可以代表差异到什么程度就是前景

完整代码:

VideoCapture cap(0);std::vector<cv::Mat> srcMats;int nBg = 200;		float wVar = 3;int cnt = 0;bool calcModel = true;cv::Mat frame;cv::Mat meanMat;cv::Mat varMat;cv::Mat dstMat;while (1){cap >> frame;cvtColor(frame, frame, COLOR_BGR2GRAY);if (cnt <= nBg) {srcMats.push_back(frame);if (cnt == 0) {std::cout << "--- reading frame --- " << std::endl;}else {std::cout << "-";if (cnt % 50 == 0)std::cout << std::endl;}}else {if (calcModel) {std::cout << std::endl << "calculating background models" << std::endl;//计算模型meanMat.create(frame.size(), CV_8UC1);varMat.create(frame.size(), CV_32FC1);//调用计算模型函数calcGaussianBackground(srcMats, meanMat, varMat);}calcModel = false;//背景差分dstMat.create(frame.size(), CV_8UC1);//利用均值mat和方差mat,计算差分gaussianThreshold(frame, meanMat, varMat, wVar, dstMat);imshow("result", dstMat);imshow("frame", frame);}if (waitKey(30) == 27) {destroyAllWindows();break;}cnt++;}


opencv自带的背景差分方式

	// OPENCV的自带背景差分方式VideoCapture cap(0);	Mat inputFrame, frame, foregroundMask, foreground, background;int method = 0;Ptr<BackgroundSubtractor> model;if (method == 0) {model = createBackgroundSubtractorKNN();}else if (method == 1) {model = createBackgroundSubtractorMOG2();}else {cout << "Can not create background model using provided method: '" << method << "'" << endl;}bool doUpdateModel = true;bool doSmoothMask = false;while (1) {cap >> frame;model->apply(frame, foregroundMask, doUpdateModel ? -1 : 0);imshow("image", frame);if (doSmoothMask){GaussianBlur(foregroundMask, foregroundMask, Size(11, 11), 3.5, 3.5);threshold(foregroundMask, foregroundMask, 10, 255, THRESH_BINARY);}if (foreground.empty())foreground.create(frame.size(), frame.type());foreground = Scalar::all(0);frame.copyTo(foreground, foregroundMask);imshow("foreground mask", foregroundMask);imshow("foreground image", foreground);model->getBackgroundImage(background);if (!background.empty())imshow("mean background image", background);const char key = (char)waitKey(30);if (key == 27 || key == 'q') // ESC{cout << "Exit requested" << endl;break;}else if (key == ' '){doUpdateModel = !doUpdateModel;cout << "Toggle background update: " << (doUpdateModel ? "ON" : "OFF") << endl;}else if (key == 's'){doSmoothMask = !doSmoothMask;cout << "Toggle foreground mask smoothing: " << (doSmoothMask ? "ON" : "OFF") << endl;}}return 0;
}

 S是是否平滑 会用高斯滤波来平滑图像

空格是是否更新背景

目前不是太懂这里的代码 希望后续学到这里后会明白

http://www.lryc.cn/news/124055.html

相关文章:

  • ES使用心得
  • Stable Diffusion - 幻想 (Fantasy) 风格与糖果世界 (Candy Land) 人物提示词配置
  • 部署K8S集群
  • 在时间和频率域中准确地测量太阳黑子活动及使用信号处理工具箱(TM)生成广泛的波形,如正弦波、方波等研究(Matlab代码实现)
  • 一百五十四、Kettle——Linux上安装Kettle9.3(踩坑,亲测有效,附截图)
  • PackageNotFoundError: No package metadata was found for bitsandbytes解决方案
  • uni-app和springboot完成前端后端对称加密解密流程
  • 【Unity造轮子】制作一个简单的2d抓勾效果(类似蜘蛛侠的技能)
  • Unity 人物连招(三段连击)
  • 关于WSL以及docker连接adb的坑
  • python安装第三方包时报错:...\lib\site-packages\pip\_vendor\urllib3\response.py...
  • 腾讯云从业者认证考试考点——云存储产品
  • 猿辅导Motiff与IXDC达成战略合作,将在UI设计领域推动AI革新更多可能性
  • 条件操作符(三目操作符)
  • (五)Unity开发Vision Pro——FAQ
  • GitOps 与 DevOps:了解关键差异,为企业做出最佳选择
  • Java实现Word文档转PDF,PDF转Word,PDF转Excel,PDF转换工具
  • Docker部署ES服务,全量同步的时候内存爆炸,ES自动关闭,CPU100%
  • Python——添加照片边框
  • 《高性能MySQL》——查询性能优化(笔记)
  • 【Linux操作系统】编译过程中遇到的问题-为什么加-c?执行文件提示无法执行二进制文件?main函数参数argc和*argv[]的作用和理解?
  • 【数据结构与算法——TypeScript】图结构(Graph)
  • C语言字符串拷贝函数详解及示例代码
  • IntelliJ IDEA热部署:JRebel插件的安装与使用
  • iTOP-3568开发板使用OpenCV处理图像-颜色转换
  • Python技巧----解压序列/可迭代对象赋值给多个变量
  • 16.3.2 【Linux】程序的管理
  • Linux命令200例:date用于显示和设置系统的日期和时间
  • excel入门
  • 单模光纤模场强度分布以及高斯近似的MATLAB仿真