图像处理: C语言中的Canny边缘检测

电脑杂谈  发布时间:2020-06-03 01:04:37  来源:网络整理

图像拼接算法代码_图像特征提取算法代码_图像识别算法c 代码

最近,我在一辆智能汽车上工作,在处理轨道图像时,我发现光线对图像的影响特别大,尤其是对于低角度广角相机而言.

测量后,使用Canny边缘检测对图像进行处理以获得图像的边缘.

让我们先看一下效果:

在上图中,我自己通过matlab验证了图像,并将其与matlab随附的canny边缘检测进行了比较. 这看起来不错的样子. 经过对微控制器的测试,我发现效果非常好. 侧面的故意照明对图像影响很小.

图像的边缘是指图像局部区域的亮度发生明显变化的部分. 从一个较小的缓冲区的灰度值急剧变化到另一个灰度级的灰度级差异很大,通常可以将此区域的灰度级轮廓视为一个步骤.

图像识别算法c 代码_图像拼接算法代码_图像特征提取算法代码

(1)必须满足两个条件: ①可以有效地抑制噪声; ②必须尽可能准确地确定边缘的位置.

(2)根据信噪比和定位积的测量结果,获得最佳逼近算子. 这是Canny边缘检测运算符.

(3)与Marr(LoG)边缘检测方法类似,它也属于先平滑然后计算导数的方法.

步骤1: 使用高斯滤镜平滑原始图像;

步骤2: 使用一阶偏导数的有限差分来计算梯度的大小和方向;

第3步: 梯度幅度的非最大抑制;

图像拼接算法代码_图像识别算法c 代码_图像特征提取算法代码

第4步: 使用双阈值算法检测并连接边缘.

以上摘录来自: blog.csdn.net/humanking7/article/details/46606791

代码如下:

/*-------------Canny算法检测边缘---------------LQ--
==============================================LQ=
 * Gx:
 *     1  -1
 *     1  -1
 *---------------
 * Gy:
 *    -1  -1
 *     1   1
*----------------------------------------
% 输入:
% org:图像,如果不是灰度图转成灰度图
% lowThr:低阈值
% 输出:
% ImgEdge: 两个偏导的平方差,反映了边缘的强度
% Sector:将方向分为3个区域,具体如下
% ------->x
% |3 2 1
% |0 X 0
% |1 2 3
% V
% y
*---------------------------------------*/
void CannyEdgeTest( uint8 org[70][120], uint8 lowThr )
{
	uint8 Sector[70][120] = {0}; //像素梯度所在扇区
	float Temp[9] = {0}; //双阈值检测临时数组
	//float TemMax = 0; //临时最大值                                                                    
	//float theta = 0; //梯度方向
	int Xg = 0; //X方向梯度
	int Yg = 0; //Y方向梯度
	
	uint8 x, y;
	uint8 ratio = 2; //高低阈值检测比例
	uint8 highThr =  50; // ratio*lowThr; //高阈值
	uint8 loss = 2; //非极大值抑制补偿,增加边缘
	
	//==========求解梯度,幅度和方向===========
	for(y=0; y<69; y++) //最下面一行不处理
	{
		for(x=0; x<119; x++) //最上一列不处理
		{
			Xg =  org[y][x] + org[y+1][x] - org[y][x+1] - org[y+1][x+1]; //计算X方向梯度
			Yg = -org[y][x] + org[y+1][x] - org[y][x+1] + org[y+1][x+1]; //计算Y方向梯度
			A[y][x] = Fsqrt(Xg*Xg+Yg*Yg); //求幅值,快速开平方算法
			Sector[y][x] = Atan2(Yg, Xg);  //求梯度方向分区 			
		} //end of for(i)	
	} //end of for(j)

	//===============非极大值抑制================
	for(y=1; y<69; y++)
	{
		for(x=0; x<119; x++)
		{
			if(0 == Sector[y][x])) //水平方向
			{
				if( (A[y][x] > A[y][x+1] - loss) && A[y][x] > (A[y][x-1] - loss) )
				{
					A[y][x] = A[y][x];
				}
				else
				{
					A[y][x] = 0;
				}
				
			} // end of 0
			if(1 == Sector[y][x]) //右上、左下
			{
				if( A[y][x] > (A[y-1][x+1] - loss) && A[y][x] > (A[y+1][x-1] - loss) )
				{
					A[y][x] = A[y][x];
				}
				else
				{
					A[y][x] = 0;
				}
			} //end of 1
			if(2 == Sector[y][x]) //竖直方向
			{
				if( A[y][x] > (A[y-1][x] - loss) && A[y][x] > (A[y+1][x] - loss) )
				{
					A[y][x] = A[y][x];
				}
				else
				{
					A[y][x] = 0;
				}
			} //end of 2
			if(3 == Sector[y][x]) //左上、右下
			{
				if( A[y][x] > (A[y-1][x-1] - loss) && A[y][x] > (A[y+1][x+1] - loss) )
				{
					A[y][x] = A[y][x];
				}
				else
				{
					A[y][x] = 0;
				}
			} //end of 3	
		} //end of for(x)
	} // end of for(y)
	
	//=============双阈值检测=================
	for(y=1; y<68; y++)
	{
		for(x=1; x<119; x++)
		{
			if( A[y][x] < lowThr ) //低于低阈值
			{
				ImgEdge[y][x] = 0;
			}
			else if( A[y][x] > highThr ) //高于高阈值
			{
				ImgEdge[y][x] = 1; 
			}
			else 
			{
				Temp[0] = A[y+1][x-1]; Temp[1] = A[y+1][x]; Temp[2] = A[y+1][x+1];
				Temp[3] = A[y][x-1];   Temp[4] = A[y][x];   Temp[5] = A[y][X+1];
				Temp[6] = A[y-1][x-1]; Temp[7] = A[y-1][x]; Temp[8] = A[y-1][x+1]; //3x3区域内点
				Quicksort(Temp, 9, 0, 8); //快速排序,低到高
				
				if(Temp[8] > highThr)
				{
					ImgEdge[y][x] = 1;
					A[y][x] = 1;
				} //end of if
				else
				{
					ImgEdge[y][x] = 0;
					A[y][x] = 0;
				} //end of if else	
			} //end of if else	
		} //end of for(x)
	} //end of for(y)
} //end of 

为了提高单片机的处理速度图像识别算法c 代码,在几个关键功能上花了很多功夫.

首先,需要平方根算法来找到梯度大小,但是传统的平方根算法太慢. 经过一番搜索,我发现了一种特别快速的处方算法. 以下是代码:

图像识别算法c 代码_图像特征提取算法代码_图像拼接算法代码

//======== 快速开方 原理不懂,快!好用!=======LQ==
float Fsqrt(float x) 
{
  float xhalf = 0.5f * x;
  int i = *(int*)&x;         // evil floating point bit level hacking
  //i = 0x5f3759df - (i >> 1);  // what the fuck?
  i  = 0X5F3504F3 - ( i >> 1 ); //精度更高
  x = *(float*)&i;
  x = x*(1.5f-(xhalf*x*x));
  return 1/x;
} //end of function Fsqrt

该算法可能是SGI在1990年代初发明的,后来在1999年的Quake III Arena的源代码中应用,但直到2002-2003年才在Usenet之类的公共网络中使用. 出现在论坛上. 该算法的优势在于,当找到倒数平方根时,它减少了浮点算术运算的巨大计算成本. 在计算机图形学领域图像识别算法c 代码,如果需要照明和投影的起伏角度以及反射效果,通常需要计算倒数平方根. [摘自百度]

当然,还有一个梯度方向. 这个东西需要计算为反正切,这很费时. 我该怎么办?

由于该canny算法仅需要知道梯度的近似方向,因此总共有八个方向,对应于一个像素周围的八个像素. 因此,经过一番思考,我解决了这样的难题:

//=============反正切函数============LQ==
/********************************************
*  直接计算几个分界点的值,只需判断 y/x 的值所
* 对应的角度在哪个范围即可,不用实时求atan
*--------------------------------------------
*    角度范围        |         弧度范围
*--------------------------------------------
* 0     ~ 22.5  ------> 0         ~ 0.3926990
* 22.5  ~ 67.5  ------> 0.3926990 ~ 1.1780972
* 67.5  ~ 112.5 ------> 1.1780972 ~ 1.9634954
* 112.5 ~ 157.5 ------> 1.9634954 ~ 2.7488935
* 157.5 ~ 180   ------> 2.7488935 ~ 3.1415926
*--------------------------------------------
*         y/x值对应弧度
*  0          ----  0.41421356  水平方向
*  0.41421347 ----  2.41421356  右上、左下
*  2.41421326 ---- -2.41421356  竖直方向
* -2.41421362 ---- -0.41421356  左上、右下
* -0.41421365 ----  0           水平方向
********************************************/
uint8 Atan2(float y, float x)
{
	float tanNum;
	uint8 alpha; //返回角度
	tanNum = y/x;
		if( tanNum> -0.41421365 && tanNum< 0.41421356 )
		{
			alpha = 0; //水平方向
		}
		else if( tanNum>= 0.41421356 && tanNum< 2.41421356)
		{
			alpha = 1; //右上、左下
		}
		else if( tanNum<= -0.41421356 && tanNum> -2.41421362)
		{
			alpha = 3; //左上、右下
		}
		else 
		{
			alpha = 2; //竖直方向
		}
 
    return alpha; //方向
} //end of function Atan2


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-231793-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 杨帅
      杨帅

      物价高是因为中国国内税率过高跟央行印钞量过大的结果

    • 唐甜
      唐甜

      鬼话

    热点图片
    拼命载入中...