【Paper】火灾尖角检测方法

在一些国内的论文中看到尖角检测方法,感觉有点类似以前学过的“种子填充”或者“扫描线”。


算法描述

按照从上到下,从左到右的顺序扫描整个二值图像。遇到像素为白色时不做任何标记,继续扫描下一像素;遇到黑色像素,则判断周围像素是否被标记的情况来决定本像素的标记情况。可分为4种情况:

  1. 若该像素的上方和左方除了0和255外没有其它的标记,则将该像素设置一个新的标记;
  2. 若该像素上方有除了0和255外其它的标记而左方没有,则设置为和上方像素相同的标记;
  3. 若该像素左方有除了0和255外其它的标记而上方没有,则设置为和左方像素相同的标记;
  4. 若该像素的上方和左方除了0和255外都有其它的标记,如果上方和左方的标记相同,则将该像素

设置为和该标记相同的标记;如果上方和左方的标记不相同,将该像素设置为和上方像素相同的标记,然后将左方重新标记。重新标记是将该像素的左方与之连续且和它左边的像素标号一样的像素点都重新标记为和当前像素一样的标记,当遇到亮点即像素值为255或图像边界或与需要重新标记的标号不一致时重新标记结束。处理结束后扫描下一像素,扫描完一行进入下一行,遇到黑色的像素点处理方法和以上相同。所有处理结束后再对整个图像扫描一遍,统计尖角的数目,计算每个尖角所在联通区域的面积(即该区域内的像素点数)以及它们的高度。

论文中的一个示意图:



代码实现

自己写的比较笨拙的代码:

void FireDetector::CheckTaperAngle(Mat &img)
{
	int dilation_type = MORPH_RECT;
	int dilation_size=5;
	Mat element = getStructuringElement( dilation_type,
		Size( 2*dilation_size + 1, 2*dilation_size+1 ),
		Point( dilation_size, dilation_size ) );
	Mat copyImage,angGray;
	img.copyTo(copyImage);
	dilate(copyImage,copyImage,Mat());
	dilate(copyImage,copyImage,Mat());
	copyImage.copyTo(angGray);
	//imshow("dilage",img);
	int nrows=angGray.rows;
	int ncols=angGray.cols;
	
	//cvtColor(copyImage,angGray,CV_BGR2GRAY);
	
	int flag=1;
	for(int i=0;i<nrows;i++){
		uchar *pimg=copyImage.ptr<uchar>(i);
		uchar *pgray=angGray.ptr<uchar>(i);
		for(int j=0;j<ncols;j++){
			if(pimg[j]>0){
				if(i>0&&j>0){
					uchar* ppgray=angGray.ptr<uchar>(i-1);
					if(ppgray[j]==0&&pgray[j-1]==0)
						pgray[j]=flag++;
					else if(ppgray[j]>0&&pgray[j-1]==0){
						pgray[j]=ppgray[j];
					}
					else if(pgray[j-1]>0&&ppgray[j]==0){
						pgray[j]=pgray[j-1];
					}
					else if(pgray[j-1]>0&&ppgray[j]>0&&pgray[j-1]==ppgray[j]){
						pgray[j]=pgray[j-1];
					}
					else{
						ppgray[j]=flag++;
						pgray[j]=ppgray[j];
						uchar tmp=pgray[j-1];
						for(int k=j-1;k>0;k--){
							if(pgray[k]==tmp)
								pgray[k]=pgray[j];
						}
					}
				}// end if: i>0&&j>0
				else if(j>0&&i==0){
					if(pgray[j-1]>0)
						pgray[j]=pgray[j-1];
					else
						pgray[j]=flag++;
				} //end else if: j>0&&i==0
				else if (i>0&&j==0){
					uchar *ppgray =angGray.ptr<uchar>(i-1);
					if(ppgray[j]>0)
						pgray[j]=ppgray[j];
					else
						ppgray[j]=flag++;
				} //end else if: i>0&&j==0
				else{
					pgray[j]=flag++;
				}
			} // end if: pimg[j]>0
		} //end for: int j=0;j<ncols;j++
	} //end for: int i=0;i<nrows;i++
	//imshow("AngleGray",angGray);

	//标记完后画尖角的图
	Mat table = (Mat_<double>(10,3) <<  0, 0, 1 , 0.5, 0.4, 0.25, 0.5, 0.5, 0.5, 0, 1, 0, 1, 0.8, 0, 1, 0.5, 1, 1, 0, 1 , 1, 0, 0, 1, 1, 1, 1, 1, 0 );
	cvtColor(angGray,angleImg,CV_GRAY2BGR);
	int channels=angleImg.channels();
	for(int i=0;i<nrows;i++){
		uchar* pgray=angGray.ptr<uchar>(i);
		uchar* pang=angleImg.ptr<uchar>(i);
		for(int j=0,jcol=0;j<ncols,jcol<ncols*channels;j++,jcol+=channels){
			uchar flagvalue=pgray[j];
			if(flagvalue>0){
				for(int k=0;k<3;k++){
					int indexpix=(int)(flagvalue%10);
					double tmp= table.at<double>(indexpix,2-k);
					pang[jcol+k]=(uchar)tmp*255;
				} // end for: k
			}
		} //end for: j
	} //end for: i
//	cout<<flag<<endl;
//	imshow("Taper angle",angleImg);
}

实验效果

代码中“画尖角图”的部分使用了很多颜色,只是希望显示出一个尖角一种颜色的视觉效果:


原场景是这样的:


这种方法就是对像素太敏感了,一个像素的突出也会计算为尖角,实用性比较差。


参考文献

[1]顾俊傻 赵敏 吴毅杰.早期火灾火焰尖角计算算法的研究[J].青岛大学学报,2010,25(1):24-27.


(转载请注明作者和出处:http://blog.csdn.net/xiaowei_cqu未经允许请勿用于商业用途)



import cv2 as cv import numpy as np """"" cv2.cornerHarris() 可以用来进行角点检测。参数如下: • img - 数据类型为 float32 的输入图像。 • blockSize - 角点检测中要考虑的领域大小。 • ksize - Sobel 求导中使用的窗口大小 • k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06] """"" src_inital = cv.imread("E:/opencv/picture/building.jpg") src = cv.cvtColor(src_inital,cv.COLOR_BGR2GRAY) src = np.float32(src) dst = cv.cornerHarris(src,3,3,0.04) #R值是由det(M)-K(trace(M))*(trace(M)),当该点是角点时,该点所对应的R值就会很大,通过设置对R的阈值,就可以筛选得到角点 #这里的dst就是R值构成的灰度图像,灰度图像坐标会与原图像对应,R值就是角点分数,当R值很大的时候 就可以认为这个点是一个角点 print(dst.shape) src_inital[dst>0.08*dst.max()]=[0,0,255] """"" src_inital[dst>0.08*dst.max()]=[0,0,255] 这句话来分析一下 dst>0.08*dst.max()这么多返回是满足条件的dst索引值,根据索引值来设置这个点的颜色 这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点 dst其实就是一个个角度分数R组成的,当λ1和λ2都很大,R 也很大,(λ1和λ2中的最小值都大于阈值)说明这个区域是角点。 那么这里为什么要大于0.08×dst.max()呢 注意了这里R是一个很大的值,我们选取里面最大的R,然后只要dst里面的值大于百分之八的R的最大值  那么此时这个dst的R值也是很大的 可以判定他为角点,也不一定要0.08可以根据图像自己选取不过如果太小的话 可能会多圈出几个不同的角点 """"" cv.imshow("inital_window",src_inital) cv.waitKey(0) cv.destroyAllWindows() 目标: 理解Harris角点检测的概念 使用函数cv2.cornerHarris(),cv2.cornerSubPix() 原理: Harris 角点检测方法大概原理就是建立一个窗口区域,然后以当前窗口为中心向各个方向进行偏移。 如上图所示,第一个窗口向各个方向偏移的时候,像素值没有变化,因为窗口偏移的时候没有遇到任何边缘信息。 第二个图,窗口当中有一个直线(即block是在边缘上),如果当前窗口进行上下的移动,也没有像素值发生变化(在其他方向上灰度值也会变化)。 第三个图,窗口覆盖了一个“拐角”,如果窗口进行偏移,任何方向上都会有像素变化。 所以,第三张图片判断为检测到角点。 判断特征点是否为角点的依据:R只与M值有关,R为大数值正数时特征点为角点,R为大数值负数时为边缘,R为小数值时为平坦区 寻找R位于一定阈值之上的局部最大值,去除伪角点。 方向导数IxIx和IyIy可以使用cv2.Sobel()函数得到 Harris角点检测的结果是灰度图,图中的值为角点检测的打分值。需要选取合适的阈值对结果进行二值化来检测角点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值