数字图像课程工程大作业分析

试题分析:
在连续的视频中对火焰及水柱的轨迹检测,效果如图。
在这里插入图片描述
**
提示:
1、火焰可利用亮度和颜色
2、水柱的轨迹需要先用背景差分获得水柱的连通域,然后利用连通域上的像素点进行曲线的拟合,水枪的位置视为已知,即可以手动活动坐标。**

1、火焰检测

我们先截一张图,观察HSV三个通道图长什么样子:

观察之后决定从S通道着手,首先确定火焰的位置是固定不变的(总是在右下角)
对S通道的图片进行二值化获得二值图,再通过限制像素位置,排除干扰:

在这里插入图片描述
对灰度图进行二值化,发现限制200时,字的影响消失
在这里插入图片描述

//识别并标出火焰
//输入 原图像 输出:原图像上框出框框(火)
void find_fire(Mat& srcMat, Mat& outputMat)
{Mat gray_srcMat;Mat dstMat, binMat;cvtColor(srcMat, gray_srcMat, COLOR_BGR2GRAY);Mat fire_Mat = Mat::zeros(gray_srcMat.size(), gray_srcMat.type());cvtColor(srcMat, dstMat, COLOR_BGR2HSV);vector<Mat> channels;split(dstMat, channels);//将S通道的图像复制,然后处理Mat S_Mat;channels.at(1).copyTo(S_Mat);int row_num = srcMat.rows;			//行数int col_num = srcMat.cols;			//列数//双重循环,遍历右下角像素值for (int i = row_num * 0.75;i < row_num;i++)	//行循环{for (int j = col_num * 0.75;j < col_num;j++)	//列循环{//-------【开始处理每个像素】---------------if ((gray_srcMat.at<uchar>(i, j) >= 150 && S_Mat.at<uchar>(i, j) >= 120)){fire_Mat.at<uchar>(i, j) = 255;}//-------【处理结束】---------------}}//膨胀Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));	//返回的是内核矩阵Mat firedstImage;dilate(fire_Mat, fire_Mat, element);//通过findContours函数寻找连通域vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(fire_Mat, contours, RETR_LIST, CHAIN_APPROX_NONE);//绘制轮廓for (int i = 0; i < contours.size(); i++) {RotatedRect rbox = minAreaRect(contours[i]);drawContours(srcMat, contours, i, Scalar(0, 255, 255), 1, 8);Point2f vtx[4];rbox.points(vtx);for (int j = 0; j < 4; ++j) {cv::line(outputMat, vtx[j], vtx[j < 3 ? j + 1 : 0], Scalar(255, 255, 255), 2, LINE_AA);}}
}

2、水柱检测

利用最简单的背景差分(帧差法),获得图像:
1
框出来的地方是误差,我们对其进行排除

//输入:图片 输出:去除干扰后的图
void clear_other_disturb(Mat& srcMa)
{//通过观察、发现0-180列为干扰,320-480列且0-90行为干扰for (int i = 0;i < 90;i++)	//行循环{for (int j = 320;j < srcMa.cols;j++)	//列循环{//-------【开始处理每个像素】---------------srcMa.at<uchar>(i, j) = 0;//-------【处理结束】---------------}}for (int i = 0;i < srcMa.rows;i++)	//行循环{for (int j = 0;j < 180;j++)	//列循环{//-------【开始处理每个像素】---------------srcMa.at<uchar>(i, j) = 0;//-------【处理结束】---------------}}
}

在这里插入图片描述
二值化一下:
在这里插入图片描述
接下来选择拟合的点:
连通域中的像素坐标:

//输入:二值化图片  输出:点集 (每列最多只有一个点,符合函数一一映射的关系)
void find_point(Mat& binMat, std::vector<cv::Point>& key_point)
{//第一个点肯定是水枪位置//遍历:170列到430列//		30行到230行//遍历方式:遍历每列,从上往下遍历(小到大),找到的第一个为白的点记录下来,如果遍历完这一列并没有发现白色点,则不作记录//注意这里的循环方式与其他地方的相反for (int i = 170;i < 430;i++)	//列循环{for (int j =30;j < 230;j++)	//行循环{if (binMat.at<uchar>(j, i) == 255){//行列与坐标系对应关系//行rows: Y(height)//列cols : X(width)//注意!注意!注意!//在Mat类型变量访问时下标是反着写的key_point.push_back(cv::Point(i,j));break;}}}//打印出来让我看看int N= key_point.size();for (int n = 0;n < N;n++){cout << "point"<< key_point[n].x<<" "<< key_point[n].y << endl;}//画出来Mat image = cv::Mat::zeros(binMat.rows, binMat.cols, CV_8UC3);for (int i = 0; i < key_point.size(); i++){cv::circle(image, key_point[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);}imshow("tu", image);
}

将选出的点画出来:
在这里插入图片描述
将像素点选取出来之后,接下来就是用最小二乘法拟合曲线,具体内容讲解请看:
https://blog.csdn.net/guduruyu/article/details/72866144

//输入:待拟合的点集,拟合出来的曲线的点
bool polynomial_curve_fit(std::vector<cv::Point>& key_point, int n, cv::Mat& A)
{//Number of key pointsint N = key_point.size();//构造矩阵Xcv::Mat X = cv::Mat::zeros(n + 1, n + 1, CV_64FC1);for (int i = 0; i < n + 1; i++){for (int j = 0; j < n + 1; j++){for (int k = 0; k < N; k++){X.at<double>(i, j) = X.at<double>(i, j) +std::pow(key_point[k].x, i + j);}}}//构造矩阵Ycv::Mat Y = cv::Mat::zeros(n + 1, 1, CV_64FC1);for (int i = 0; i < n + 1; i++){for (int k = 0; k < N; k++){Y.at<double>(i, 0) = Y.at<double>(i, 0) +std::pow(key_point[k].x, i) * key_point[k].y;}}A = cv::Mat::zeros(n + 1, 1, CV_64FC1);//求解矩阵Acv::solve(X, Y, A, cv::DECOMP_LU);return true;
}

最终代码:

#include <opencv2/opencv.hpp>
#include "opencv2/features2d.hpp"
#include <iostream>
#include "windows.h"
#include <stdio.h>
#include <time.h>
#include <math.h>  
#include<opencv2/imgproc/types_c.h> 
//#include "My_ImageProssing_base.h"
#define WINDOW_NAME1 "【程序窗口1】"			
#define WINDOW_NAME2 "【程序窗口2】"	
using namespace cv;
using namespace std;
RNG g_rng(12345);//识别并标出火焰
//输入 原图像 输出:原图像上框出框框(火)
void find_fire(Mat& srcMat, Mat& outputMat)
{Mat gray_srcMat;Mat dstMat, binMat;cvtColor(srcMat, gray_srcMat, COLOR_BGR2GRAY);Mat fire_Mat = Mat::zeros(gray_srcMat.size(), gray_srcMat.type());cvtColor(srcMat, dstMat, COLOR_BGR2HSV);vector<Mat> channels;split(dstMat, channels);//将S通道的图像复制,然后处理Mat S_Mat;channels.at(1).copyTo(S_Mat);int row_num = srcMat.rows;			//行数int col_num = srcMat.cols;			//列数//双重循环,遍历右下角像素值for (int i = row_num * 0.75;i < row_num;i++)	//行循环{for (int j = col_num * 0.75;j < col_num;j++)	//列循环{//-------【开始处理每个像素】---------------if ((gray_srcMat.at<uchar>(i, j) >= 150 && S_Mat.at<uchar>(i, j) >= 120)){fire_Mat.at<uchar>(i, j) = 255;}//-------【处理结束】---------------}}//膨胀Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));	//返回的是内核矩阵Mat firedstImage;dilate(fire_Mat, fire_Mat, element);//通过findContours函数寻找连通域vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(fire_Mat, contours, RETR_LIST, CHAIN_APPROX_NONE);//绘制轮廓for (int i = 0; i < contours.size(); i++) {RotatedRect rbox = minAreaRect(contours[i]);drawContours(srcMat, contours, i, Scalar(0, 255, 255), 1, 8);Point2f vtx[4];rbox.points(vtx);for (int j = 0; j < 4; ++j) {cv::line(outputMat, vtx[j], vtx[j < 3 ? j + 1 : 0], Scalar(255, 255, 255), 2, LINE_AA);}}
}
//--------------------------------------------工程大作业---------------------------------------------------//输入:二值化图片  输出:点集 (每列最多只有一个点,符合函数一一映射的关系)
void find_point(Mat& binMat, std::vector<cv::Point>& key_point)
{//第一个点肯定是水枪位置//遍历:170列到430列//		30行到230行//遍历方式:遍历每列,从上往下遍历(小到大),找到的第一个为白的点记录下来,如果遍历完这一列并没有发现白色点,则不作记录//注意这里的循环方式与其他地方的相反for (int i = 170;i < 430;i++)	//列循环{for (int j =30;j < 230;j++)	//行循环{if (binMat.at<uchar>(j, i) == 255){//行列与坐标系对应关系//行rows: Y(height)//列cols : X(width)//注意!注意!注意!//在Mat类型变量访问时下标是反着写的key_point.push_back(cv::Point(i,j));break;}}}//打印出来让我看看int N= key_point.size();for (int n = 0;n < N;n++){cout << "point"<< key_point[n].x<<" "<< key_point[n].y << endl;}//画出来Mat image = cv::Mat::zeros(binMat.rows, binMat.cols, CV_8UC3);for (int i = 0; i < key_point.size(); i++){cv::circle(image, key_point[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);}//imshow("tu", image);
}//输入:待拟合的点集,拟合出来的曲线的点
bool polynomial_curve_fit(std::vector<cv::Point>& key_point, int n, cv::Mat& A)
{//Number of key pointsint N = key_point.size();//构造矩阵Xcv::Mat X = cv::Mat::zeros(n + 1, n + 1, CV_64FC1);for (int i = 0; i < n + 1; i++){for (int j = 0; j < n + 1; j++){for (int k = 0; k < N; k++){X.at<double>(i, j) = X.at<double>(i, j) +std::pow(key_point[k].x, i + j);}}}//构造矩阵Ycv::Mat Y = cv::Mat::zeros(n + 1, 1, CV_64FC1);for (int i = 0; i < n + 1; i++){for (int k = 0; k < N; k++){Y.at<double>(i, 0) = Y.at<double>(i, 0) +std::pow(key_point[k].x, i) * key_point[k].y;}}A = cv::Mat::zeros(n + 1, 1, CV_64FC1);//求解矩阵Acv::solve(X, Y, A, cv::DECOMP_LU);return true;
}//输入:图片 输出:去除干扰后的图
void clear_other_disturb(Mat& srcMa)
{//通过观察、发现0-180列为干扰,320-480列且0-90行为干扰for (int i = 0;i < 90;i++)	//行循环{for (int j = 320;j < srcMa.cols;j++)	//列循环{//-------【开始处理每个像素】---------------srcMa.at<uchar>(i, j) = 0;//-------【处理结束】---------------}}for (int i = 0;i < srcMa.rows;i++)	//行循环{for (int j = 0;j < 180;j++)	//列循环{//-------【开始处理每个像素】---------------srcMa.at<uchar>(i, j) = 0;//-------【处理结束】---------------}}
}
int main()
{//实例化的同时初始化VideoCapture capture("D:\\opencv_picture_test\\videos\\大作业.avi");		//类似于 int a=1;//如果视频打开失败//计数器int cnt = 0;Mat frame;Mat rgb_mat;		Mat rgb_mat1;Mat bgMat1;		//第0帧图像Mat bgMat2;		//之后每帧图像while (1){capture >> frame;//图像保护if (!frame.data){cout << "src image load failed!" << endl;break;}//将彩色图保存下来,用于最后画图的底布rgb_mat = frame.clone();rgb_mat1= frame.clone();//转灰度图,用于之后的找水柱cvtColor(frame, frame, COLOR_BGR2GRAY);if (cnt == 0){//第一帧,获得背景图像frame.copyTo(bgMat1);//找火find_fire(rgb_mat, rgb_mat);imshow("output", rgb_mat);waitKey(20);}else if (cnt<=100)	//水柱还没有出现,我们不找水柱,防止误判(其实是有误判的),此时我们只绘制火焰{//找火find_fire(rgb_mat, rgb_mat);imshow("output", rgb_mat);waitKey(20);}else{//获取本次场景的图像frame.copyTo(bgMat2);//====================================进行处理================================================Mat result = bgMat1.clone();//【1】背景图像和当前图像相减absdiff(bgMat1, bgMat2, result);//【2】接下来是去除干扰clear_other_disturb(result);//【3】二值化一下threshold(result, result, 100, 255, THRESH_BINARY);//imshow("result", result);//【4】找点std::vector<cv::Point> points;find_point(result, points);//【5】找到点之后就是拟合曲线,这里采用【https://blog.csdn.net/guduruyu/article/details/72866144】的思路cv::Mat A;//这里使用3次函数,效果很好polynomial_curve_fit(points, 3, A);std::cout << "A = " << A << std::endl;std::vector<cv::Point> points_fitted;for (int x = 170; x < 430; x++){double y = A.at<double>(0, 0) + A.at<double>(1, 0) * x +A.at<double>(2, 0) * std::pow(x, 2) + A.at<double>(3, 0) * std::pow(x, 3);points_fitted.push_back(cv::Point(x, y));}//【6】在彩色图上绘制水柱cv::polylines(rgb_mat, points_fitted, false, cv::Scalar(0, 255, 255), 1, 8, 0);find_fire(rgb_mat1, rgb_mat);imshow("output", rgb_mat);//====================================处理结束================================================waitKey(20);}cnt++;}waitKey(0);return 0;
}

本文章代码可以随意使用!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计电子商务网站的10个技巧(转自ITEye)

导读&#xff1a;随着先进科学技术的应用&#xff0c;人们无需外出逛几个小时来“猎”东西&#xff0c;直接坐在家里就可以购买所需商品&#xff0c;支付服务费用。你只需一台电脑就能搞定。人们习惯了周到的服务和漂亮的橱窗&#xff0c;对网店的选择也不例外。因此&#xff0…

C++语法:vector的使用

【1】vector的创建与元素插入【2】vector元素的访问【3】vector的基本使用技巧【4】vector的几个重要操作【1】vector的创建与元素插入 std::vector<cv::Point> points; //vector容器中保存的类型是Point for (int i 0;i < 10;i) {float x rng.uniform(0, img.cols…

C++语法:求vector中的最大值及其位置

代码&#xff1a; #include <iostream> #include <vector> #include <algorithm> using namespace std;int main(){vector<int> a { 2,4,6,7,1,0,8,9,6,3,2 };auto maxPosition max_element(a.begin(), a.end());cout << *maxPosition <&l…

C#编码简单性之函数篇(如何编写简短的C#代码,随时更新)

作者&#xff1a;陈勇出处&#xff1a;blog.csdn.net/cheny_com这是编码简单性系列中的其中一篇&#xff0c;之前几篇包括代码篇和语义篇。因为要积累案例&#xff0c;会随时更新。之前提到&#xff1a;编码简单性的“心法”就是&#xff1a;只要屏幕上有任何两部分代码看上去相…

R学习笔记(1):R是什么

本文最新版已更新至http://thinkinside.tk/2013/05/03/r_notes_1_what.html 在学习量化投资的时候&#xff0c;我发现了R&#xff08;www.r-project.org&#xff09;。R到底是什么呢&#xff1f;在开始之前&#xff0c;先看看R的神奇之处。 1. R初窥 从CRAN&#xff08;The Co…

数字图像处理知识总结

一&#xff1a;基本概念 数字图像&#xff1a;指由被称作像素的小块区域组成的二维矩阵。将物理图像行列划分后&#xff0c;每个小块区域称为像素&#xff08;pixel&#xff09;。每个像素包括两个属性&#xff1a;位置和灰度。图像数字化一般分为采样、量化与编码三个步骤。数…

oracle marley,滚石杂志500大专辑,对欧美音乐感兴趣的可以找来听听。

滚石杂志于2003年11月评选出的滚石杂志五百大专辑。值得一提的是&#xff0c;披头士乐队占据了前五中的三席&#xff0c;前五十中的7席&#xff0c;正式出版的专辑几乎全部入选前五百。排名 演唱者 专辑001 披头士乐队(The Beatles) Sgt. Peppers Lonely Hearts Club Band002 海…

kinect中psi是什么_PSI的完整形式是什么?

kinect中psi是什么PSI&#xff1a;每平方英寸磅/国际人口服务 (PSI: Pound per Square Inch / Population Services International) 1)PSI&#xff1a;每平方英寸磅 (1) PSI: Pound per Square Inch) PSI is an abbreviation of Pound per Square Inch. Pound per Square Inch …

jupyter notebook指定工作目录

【1】打开Anaconda Navigator 打开Anaconda Navigator&#xff0c;点击左侧Environments&#xff0c;点击base(root)->open Terminal 【2】输入指令jupyter notebook --generate-config 按下回车键&#xff0c;弹出config所在位置。 以VS Code打开文件 【3】修改第26…

五、“嵌段共聚醚酯型”易去污整理剂的结构特点及对织物服用性的影响?

“嵌段共聚醚酯型”易去污整理剂的结构特点及对织物服用性的影响? 收集资料阶段 嵌段共聚醚酯型易去污整理剂(简称聚醚酯)是涤纶最早的一种耐久性易去污剂,其商品名称为Permalose T,由英国ICI公司生产,它能使涤纶及其混纺织物具有优良的易去污、抗湿再沾污和抗静电性能。…

linux服务器指示灯,【转】明明白白你的Linux服务器——故障篇 | 旺旺知识库

在Linux/unix服务器的维护过程中&#xff0c;遇到各种各样的问题&#xff1b;有的严重&#xff0c;有的很好解决&#xff0c;有的解决过程我就记录下来与大家分享下&#xff0c;希望能给大家带来帮助。故障一、今天早上来的第一件事&#xff0c;就是检查昨天晚上刚刚重新安装的…

构件图(Component Diagram)—UML图(八)

构件图是显示代码自身结构的实现级别的图表。构件图由诸如源代码文件、二进制代码文件、可执行文件或动态链接库 (DLL) 这样的构件构成&#xff0c;并通过依赖关系相连接 下面这张图介绍了构件图的基本内容&#xff1a; 下面这张图是个构件图的实例&#xff1a; 转载于:https:/…

GAE work

https://appengine.google.com/ can visit in Home, but cannot visit in Office.Download a java SDK for GAE, will write something here.转载于:https://www.cnblogs.com/cnyao/archive/2011/05/05/2038161.html

二进制文件签名_二进制数的签名表示

二进制文件签名Prerequisite: Number systems 先决条件&#xff1a; 数字系统 Until now, we have only talked about positive numbers and have already discussed their mathematical operations. But there also exists negative numbers in the number system, in this a…

六、解释红外线纺织品的保健、保暖作用?

解释红外线纺织品的保健、保暖作用&#xff1f; 收集资料阶段 人体既是远红外的辐射源又能吸收远红外辐射。由于人体60&#xff05;&#xff5e;70&#xff05;为水‚故人体对红外辐射吸收近似于水&#xff0c;人体组织所拥有的特定振动频率和回转周波数与人体组织中的O&…

linux yum命令作用,YUM命令使用示例

YUM或Yellowdog Updater Modified是管理rpm包的前端工具。 它用于通过命令行界面或使用图形模式来安装&#xff0c;删除&#xff0c;更新和收集有关rpm软件包的信息。 使用YUM的主要优点是&#xff0c;它解决了rpm包的所有依赖关系&#xff0c;并将它们与包一起安装。下面让我们…

PySide开发MySql远程备份工具

MySql数据库安装在机房&#xff0c;而工作人员日常办公的地方距离机房有段距离&#xff0c;且不在同一楼层。出入机房不是很方便。就想着能否给这些人员开发一个图形化的备份MySql数据库的小工具&#xff1f;使用组件如下&#xff1a;(1)Python(2)PySide(3)mysqldump其实mysql已…

HadoopSourceAnalyse --- Nodemanager Container request handler

Overview Container 是Hadoop中运行任务的地方&#xff0c;当Resourcemanager收到一任务请求后&#xff0c;会向nodemanager 请求一个Container 来运行ApplicationMaster&#xff0c; ApplicationMaster运行起来之后&#xff0c;会继续向Resourcemanager请求新的container来运行…

数据结构 二叉树的存储结构_线程二叉树| 数据结构

数据结构 二叉树的存储结构线程二叉树 (Threaded Binary Tree ) A binary tree can be represented by using array representation or linked list representation. When a binary tree is represented using linked list representation. If any node is not having a child …

八、关于防水透湿整理

1,防水透湿整理加工技术的类型? 收集资料阶段 按照加工方式分类 防水透湿织物按照加工方式可分为高密织物、涂层织物和层压织物。不同加工方式所对应的织物各有特色。高密织物产生于 20 世纪 80 年代,它的密度可达到普通织物的 20 倍。在晴朗天气时,纱线孔隙大约为 10 μm…