2015-05-17 12:00:27 zhzz2012 阅读数 2509

简介

斑点通常是指,与周围有着颜色和灰度差别的区域,

LoG检测

利用高斯拉普拉斯LOG算子检测图像斑点较DoH,Harris和其它点检测方法稳定性更好,抗图像中噪声的能力更强
二维高斯函数 g(x,y,σ)=12πσe(x2+y2)2σ
拉普拉斯变换容易受到噪点影响,因此需要在处理之前,先用高斯模糊,然后再对平滑处理后的图像进行拉普拉斯变化:Δ2[G(x,y)f(x,y)]=[δ2G(x,y)]f(x,y)=LoG(x,y)f(x,y)
上式说明可以先求高斯函数的拉普拉斯算子,然后再处理图像,证明过程如下:
ddt[h(t)f(t)]=ddtf(τ)ddth(tτ)dτ=f(t)ddth(t),在求一次到顺序就变回来了;
高斯的拉普拉斯变换为:Δ2g=2gx2+2gy2 ,高斯函数二阶导数随方差增大呈阶梯衰减现象。所以,为了去除方差导致的衰减现象,应用高斯函数的导数时,对其要进行规范化处理,规范化的高斯拉普拉斯变换为:
Δ2normg=σ2(2gx2+2gy2)=σ2Δ2g
Δ2normg的极值点,等价于求取下式:(Δ2normg)σ=0
(x2+y22σ2)ex2+y22σ2
r22σ2=0
将拉普拉斯响应到达峰值的尺度σ值,成为特征尺度,同时在空间和尺度上的最大值和最小值的点就是我们所期待的斑点,对于二维图像I(x,y),计算图像在不同尺度下的离散拉普拉斯响应值,然后,检查位置空间中每个点。如果该点的拉普拉斯响应值都大于或小于其他26个立方空间邻域的值,那么该点就是被检测到的图像斑点。

2017-03-29 18:15:31 gloriazhang2013 阅读数 991

function [points] = log_Blob(img,o_nb_blobs)
    % 功能:提取LoG斑点
    % 输入:
    %      img –输入的图像
    %       o_nb_blobs -需要检测的斑点区域的数量
    % 输出:
    %       points -检测出的斑点
    % 参考文献:
    % Lindeberg, T. Feature Detection with Automatic Scale Selection
    % IEEE Transactions Pattern Analysis Machine Intelligence, 1998, 30,
    % 77-116
   
    % 输入图像
    img = double(img(:,:,1));
       
    % 设定检测到斑点的数量
    if nargin==1
        nb_blobs = 120;
    else
        nb_blobs = o_nb_blobs;
    end
   
    % 设定LoG参数
    sigma_begin = 2;
    sigma_end   = 15;
    sigma_step  = 1;
    sigma_array = sigma_begin:sigma_step:sigma_end;
    sigma_nb    = numel(sigma_array);
       
    % 变量
    img_height  = size(img,1);
    img_width   = size(img,2);
       
    % 计算尺度规范化高斯拉普拉斯算子
    snlo = zeros(img_height,img_width,sigma_nb);
    for i=1:sigma_nb
        sigma       = sigma_array(i);

snlo(:,:,i) = sigma*sigma*imfilter(img,fspecial('log', floor(6*sigma+1), sigma),'replicate');

    end
       
    % 搜索局部极值
    snlo_dil             = imdilate(snlo,ones(3,3,3));
    blob_candidate_index = find(snlo==snlo_dil);
    blob_candidate_value = snlo(blob_candidate_index);
    [tmp,index]          = sort(blob_candidate_value,'descend');
   
blob_index           = blob_candidate_index( index(1:min(nb_blobs,numel(index))) );

[lig,col,sca]        = ind2sub([img_height,img_width,sigma_nb],blob_index);

    points               = [lig,col,3*reshape(sigma_array(sca),[size(lig,1),1])];
   
end

2016-01-05 22:21:20 horseinch 阅读数 14035

斑点是数字图像的主要特征,是区域检测的一种特例,是许多特征生成、目标识别等方法的重要预处理环节。斑点通常和关键点(keypoint)兴趣点(intrestpoint)以及特征点(featurepoint)表示同一个概念。

斑点通常指与周围有着颜色和灰度区别的区域。从远处看,一棵树是一个斑点,一块草地、一栋房子也可看成斑点。主要有LoG斑点DoH斑点以及Gilles斑点

LOG斑点检测

利用高斯拉普通拉斯(Laplace of Gaussian,LOG)算子检测图像斑点是一种十分常用的方法。

其实从更直观的角度去解释为什么LOG算子可以检测图像中的斑点是:

图像与某一个二维函数进行卷积运算实际就是求取图像与这一函数的相似性

同理,图像与高斯拉普拉斯函数的卷积实际就是求取图像与高斯拉普拉斯函数的相似性。当图像中的斑点尺寸与高斯拉普拉斯函数的形状趋近一致时,图像的拉普拉斯响应达到最大。

从概率的角度解释为:假设原图像是一个与位置有关的随机变量X的密度函数,而LOG为随机变量Y的密度函数,则随机变量X+Y的密度分布函数即为两个函数的卷积形式。如果想让X+Y能取到最大值,则X与Y能保持步调一致最好,即X上升时,Y也上升,X最大时,Y也最大。

那么LOG算子是怎么被构想出来的呢?

事实上我们知道Laplace可以用来检测图像中的局部极值点,但是对噪声敏感,所以在我们对图像进行Laplace卷积之前,我们用一个高斯低通滤波对图像进行卷积,目标是去除图像中的噪声点。这一过程 可以描述为:

先对图像 f(x,y) 用方差为 $\sigma$  的高斯核进行高斯滤波,去除图像中的噪点。

$$L(x,y;\sigma) = f(x,y) * G(x,y;\sigma)$$

然后对图像的拉普拉斯图像则为:

$$\Delta^2 = \frac{\partial^2L}{\partial x^2}+\frac{\partial^2L}{\partial y^2}$$

而实际上有下面等式:

$$\Delta^2[G(x,y)*f(x,y)] = \Delta^2[G(x,y)]*f(x,y)$$

所以,我们可以先求高斯核的拉普拉斯算子,再对图像进行卷积。

对于图像中二值化的圆形斑点,在尺度为$\sigma=r/\sqrt{2}$时,高斯拉普拉斯响应值达到最大。

同理,如果图像中的圆形斑点黑点反向,则在$\sigma=r/\sqrt{2}$时,高斯拉普拉斯响应值达到最小。将高斯拉普拉斯响应达到峰值时的尺度$\sigma$值,称为特征尺度。

如前所述,同时在空间和尺度上达到最大值(最小值)的点就是我们期望的斑点。对于计算二维图像I(x,y),计算图像在不同尺度下的离散拉普拉斯响应值,然后,检查位置空间中的每个点,如果该点的拉普拉斯响应值都大于或小于其他26个立方空间领域的值,那么,就是被检测的图像斑点。

LoG斑点的Matlab程序:

function [points]=LoG_Blob(img,num_blobs)
%功能:提取LoG斑点
%img——输入图像
%num——需要检测斑点数目
%point——检测出的斑点
img=double(img(:,:,1));
if nargin==1    %如果输入参数仅有一个(img)
    num=120;    %则将检测斑点数设置为120
else
    num=num_blobs;
end
%设定LoG参数
sigma_begin=2;
sigma_end=15;
sigma_step=1;
sigma_array=sigma_begin:sigma_step:sigma_end;
sigma_nb=numel(sigma_array);
    %n = numel(A) returns the number of elements, n, in array A
    %equivalent to prod(size(A)).
img_height=size(img,1);
img_width=size(img,2);
%计算尺度规范化高斯拉普拉斯算子
snlo=zeros(img_height,img_width,sigma_nb);
for i=1:sigma_nb
    sigma=sigma_array(i);
    snlo(:,:,i)=sigma*sigma*imfilter(img,fspecial('log',...
        floor(6*sigma+1),sigma),'replicate');
end
%搜索局部极值
snlo_dil=imdilate(snlo,ones(3,3,3));
blob_candidate_index=find(snlo==snlo_dil);
blob_candidate_value=snlo(blob_candidate_index);
[temp,index]=sort(blob_candidate_value,'descend');
blob_index=blob_candidate_index(index(1:min(num,numel(index))));
[lig,col,sca]=ind2sub([img_height,img_width,sigma_nb],blob_index);
points=[lig,col,3*reshape(sigma_array(sca),[size(lig,1),1])];
end

function draw(img,pt,str)
%功能:在图像中绘制特征点
%img——输入图像
%pt——特征点坐标
%str——图上显示的名称
figure('Name',str);
imshow(img);
hold on;
axis off;
switch size(pt,2)
    case 2
        s=2;
        for i=1:size(pt,1)
            rectangle('Position',[pt(i,2)-s,pt(i,1)-s,2*s,2*s],'Curvature'...
                ,[0,0],'EdgeColor','b','LineWidth',2);
        end
    case 3
        for i=1:size(pt,1)
            rectangle('Position',[pt(i,2)-pt(i,3),pt(i,1)-pt(i,3),...
                2*pt(i,3),2*pt(i,3)],'Curvature',[1,1],'EdgeColor',...
                'w','LineWidth',2);
        end
end
end

在matlab指令窗口输入:

img=imread('向日葵.jpg');
imshow(img);
pt=LoG_Blob(rgb2gray(img));
draw(img,pt,'LOG')

即可得到:


2015-11-26 15:51:49 zizi7 阅读数 4389

1. 原理

考虑一个一维信号,该信号在t=1000时发生了阶跃,那么如何检测这个阶跃的位置呢?

图1分别用1阶高斯导数和2阶高斯导数对该信号进行卷积


图1-1. 一阶高斯导数(左)、二阶高斯导数(右)与原始信号卷积

可以看到,一阶高斯导的卷积结果在t=1000产生了一个极值,二阶高斯导的卷积在该位置是个过零点

LOG就是利用二阶高斯导数(也叫拉普拉斯变换)与原始信号(图像)卷积,通过检测局部极值获得角点。

需要注意的是:不同方差的二阶高斯导数得到的响应是不同的,当方差与信号波动的半径匹配时获得最大响应(图1-2)


图1-2. 方差为1的二阶高斯导数与不同半径的信号(左)卷积结果(右)

但此时我们还不能愉快的利用这个性质,因为未经处理的二阶高斯导数随方差增大会发生衰减,所以可能会出现这种情况(图1-3)


图1-3. 二阶高斯导数随方差增大的衰减现象

处理的方法叫规范化,很简单,就是在导数前乘上方差的平方。


公式推导:

(1)LOG

二阶高斯函数,规范化二阶高斯函数导数

整理得,将导数对方差求导,取0值对应的极值

这个就是信号半径与方差的关系。


(2)DOH

基本思路与LOG一样,只不过使用了Hessian矩阵:,对一张图计算xx,yy,xy三个方向的卷积,然后计算其加权行列式:。理论上,与LOG相比,DOH对细长结构的斑点有较好的抑制作用。


LOG斑点检测算法步骤:

(1)预定义一组方差值(因为不知道待检信号的尺度),对每个方差生成一个二阶高斯模板

注:这里取(DOH为,生成3个模板),有个放大差异的作用;模板尺寸取 

(2)对每个方差,将对应的高斯模板与原始信号做卷积(DOH需要将三个模板分别与原始图做卷积,然后计算其加权行列式),得到一组不同尺度的图像集

(3)对每个空间位置,比较其在图像集里26(3*3*3-1)个位置(图1-4)的值,如果为极值,则认为在该点有一个斑点

通过此时的尺度值可进一步得到该斑点的半径。

 

图1-4. 在26个位置里比较


2. 代码

#define MAXPOINTS 50000
typedef struct myPoint
{
	int x;
	int y;
	int radiu;
}_point;

void getLOGkernel(int halfWin, float sita, float** kernel);
void cornerLOG(unsigned char* srcImg, _point* corner, int* count, int height, int width, float minScale, float maxScale, int stepScale);
void converlution(unsigned char* srcImg, int** dstImg, int height, int width, float* kernel, int kernelWin);
bool isMax(int* compImg, int compValue, _point compPoint, int kerWin, int imgWidth, bool isSameK);
void cornerDOH(unsigned char* srcImg, _point* corner, int* count, int height, int width, float minScale, float maxScale, int stepScale);
void getDOHkernel(int halfWin, float sita, float** kernelxx, float** kernelyy, float** kernelxy);
void detValue(int** scaleimg, int* imgxx, int* imgyy, int* imgxy, float scale, int height, int width);

void main()
{
	_point corner[MAXPOINTS];
	int numCorner = 0;
	float minScale = 1;
	float maxScale = 20;
	float stepScale = 2;
	unsigned char* srcImg = NULL;

	cv::Mat img = cv::imread("../file/sunflowers.jpg", 0);
	int height = img.rows;
	int width = img.cols;
	srcImg = new unsigned char[height*width];
	for(int i=0; i<height; i++)
	{
		uchar* ptr = img.ptr<uchar>(i);
		for(int j=0; j<width; j++)
			srcImg[i*width+j] = ptr[j];
	}
#if 1
	cornerLOG(srcImg, corner, &numCorner, height, width, minScale, maxScale, stepScale);
#else
	cornerDOH(srcImg, corner, &numCorner, height, width, minScale, maxScale, stepScale);
#endif
	delete[] srcImg;

	cv::Mat showImg;
	cvtColor(img, showImg, CV_GRAY2BGR);
	for(int i=0; i<numCorner; i++)
	{
		cv::Point cor(corner[i].x, corner[i].y);
		cv::circle(showImg, cor, corner[i].radiu, cv::Scalar(0,0,255));
	}

	cv::namedWindow("show");
	cv::imshow("show", showImg);
	cv::waitKey(0);
}

void getLOGkernel(int halfWin, float sita, float** kernel)
{
	int winSize = 2*halfWin+1;
	float tmp1, tmp2, sumValue = 0;
	float powsita = sita*sita;
	for(int i=-halfWin; i<=halfWin; i++)
	{
		for(int j=-halfWin; j<=halfWin; j++)
		{
			tmp1 = -1*(i*i+j*j)/(2*powsita);
			tmp2 = exp(tmp1)*(i*i+j*j-2*powsita);//exp(tmp1)*(1+tmp1)/(-1*powsita*powsita);
			sumValue += tmp2;
			(*kernel)[(i+halfWin)*winSize+(j+halfWin)] = tmp2;
		}
	}
	for(int i=0; i<winSize*winSize; i++)
		(*kernel)[i] -= sumValue/(winSize*winSize);
}

void converlution(unsigned char* srcImg, int** dstImg, int height, int width, float* kernel, int kernelWin)
{
	for(int i=0; i<height; i++)
	{
		for(int j=0; j<width; j++)
		{
			float sumValue = 0;
			int count = 0;
			for(int m=i-kernelWin; m<=i+kernelWin; m++)
			{
				for(int n=j-kernelWin; n<=j+kernelWin; n++)
				{
					if(m>=0 && m<height && n>=0 && n<width)
						sumValue += int(srcImg[m*width+n])*kernel[count];
					count++;
				}
			}
			sumValue *= 100;
			(*dstImg)[i*width+j] = int(sumValue);
		}
	}
}

bool isMax(int* compImg, int compValue, _point compPoint, int kerWin, int imgWidth, bool isSameK)
{
	for(int i=compPoint.y-kerWin; i<=compPoint.y+kerWin; i++)
	{
		for(int j=compPoint.x-kerWin; j<=compPoint.x+kerWin; j++)
		{
			if(isSameK && i==compPoint.y && j==compPoint.x)
				continue;
			if(abs(compValue) <= abs(compImg[i*imgWidth+j]))
				return false;
		}
	}
	return true;
}

void cornerLOG(unsigned char* srcImg, _point* corner, int* count, int height, int width, float minScale, float maxScale, int stepScale)
{
	int numScale = int((maxScale - minScale)/stepScale);
	int** scaledImg = new int*[numScale]; 
	for(int i=0; i<numScale; i++)
		scaledImg[i] = new int[height*width];

	for(int k=0; k<numScale; k++)
	{
		float scale = minScale+stepScale*k;
		int kernelWin = 3*scale;
		float *kernel = new float[(2*kernelWin+1)*(2*kernelWin+1)];
		getLOGkernel(kernelWin, scale, &kernel);
		converlution(srcImg, &(scaledImg[k]), height, width, kernel, kernelWin);
		delete[] kernel;
	}

	*count = 0;
	for(int i=1; i<height-1; i++)
	{
		for(int j=1; j<width-1; j++)
		{
			for(int k=1; k<numScale-1; k++)
			{
				if((*count)>=MAXPOINTS)
				{
					for(int m=0; m<numScale; m++)
						delete[] scaledImg[m];
					delete[] scaledImg;

					return;
				}

				_point cp;
				cp.x = j;
				cp.y = i;
				float scale = minScale+k*stepScale;
				cp.radiu = int(1.414*scale+0.5);
				if(isMax(scaledImg[k-1], scaledImg[k][i*width+j], cp, 1, width, false) &&
					isMax(scaledImg[k], scaledImg[k][i*width+j], cp, 1, width, true) &&
					isMax(scaledImg[k+1], scaledImg[k][i*width+j], cp, 1, width, false))
				{
					corner[(*count)++] = cp;
					break;
				}
			}
		}
	}

	for(int i=0; i<numScale; i++)
		delete[] scaledImg[i];
	delete[] scaledImg;
}

void getDOHkernel(int halfWin, float sita, float** kernelxx, float** kernelyy, float** kernelxy)
{
	int winSize = 2*halfWin+1;
	float tmp1, tmpxx, tmpyy, tmpxy;
	float sumValuexx = 0, sumValueyy = 0, sumValuexy = 0;
	float powsita = sita*sita;
	for(int i=-halfWin; i<=halfWin; i++)
	{
		for(int j=-halfWin; j<=halfWin; j++)
		{
			tmp1 = -1*(i*i+j*j)/(2*powsita);
			tmpxx = exp(tmp1)*(j*j-powsita);
			tmpyy = exp(tmp1)*(i*i-powsita);
			tmpxy = exp(tmp1)*i*j;

			sumValuexx += tmpxx;
			sumValueyy += tmpyy;
			sumValuexy += tmpxy;

			(*kernelxx)[(i+halfWin)*winSize+(j+halfWin)] = tmpxx;
			(*kernelyy)[(i+halfWin)*winSize+(j+halfWin)] = tmpyy;
			(*kernelxy)[(i+halfWin)*winSize+(j+halfWin)] = tmpxy;
		}
	}
	for(int i=0; i<winSize*winSize; i++)
	{
		(*kernelxx)[i] -= sumValuexx/(winSize*winSize);
		(*kernelyy)[i] -= sumValueyy/(winSize*winSize);
		(*kernelxy)[i] -= sumValuexy/(winSize*winSize);
	}
}

void detValue(int** imgscale, int* imgxx, int* imgyy, int* imgxy, float scale, int height, int width)
{
	for(int i=0; i<height; i++)
	{
		for(int j=0; j<width; j++)
		{
			float xx = imgxx[i*width+j]/100.0;
			float yy = imgyy[i*width+j]/100.0;
			float xy = imgxy[i*width+j]/100.0;
			int vv = xx*yy-xy*xy;
			(*imgscale)[i*width+j] = int(vv/(scale*scale));
		}
	}
}

void cornerDOH(unsigned char* srcImg, _point* corner, int* count, int height, int width, float minScale, float maxScale, int stepScale)
{
	int numScale = int((maxScale - minScale)/stepScale);
	int** scaledImg = new int*[numScale]; 
	for(int i=0; i<numScale; i++)
		scaledImg[i] = new int[height*width];

	for(int k=0; k<numScale; k++)
	{
		float scale = minScale+stepScale*k;
		int kernelWin = 3*scale;
		float *kernelxx = new float[(2*kernelWin+1)*(2*kernelWin+1)];
		float *kernelyy = new float[(2*kernelWin+1)*(2*kernelWin+1)];
		float *kernelxy = new float[(2*kernelWin+1)*(2*kernelWin+1)];
		getDOHkernel(kernelWin, scale, &kernelxx, &kernelyy, &kernelxy);

		int** tmpImg = new int*[3]; 
		for(int i=0; i<3; i++)
			tmpImg[i] = new int[height*width];
		converlution(srcImg, &(tmpImg[0]), height, width, kernelxx, kernelWin);
		converlution(srcImg, &(tmpImg[1]), height, width, kernelyy, kernelWin);
		converlution(srcImg, &(tmpImg[2]), height, width, kernelxy, kernelWin);

		detValue(&(scaledImg[k]), tmpImg[0], tmpImg[1], tmpImg[2], scale, height, width);

		for(int i=0; i<3; i++)
			delete[] tmpImg[i];
		delete[] tmpImg;
		delete[] kernelxx;
		delete[] kernelyy;
		delete[] kernelxy;
	}

	*count = 0;
	for(int i=1; i<height-1; i++)
	{
		for(int j=1; j<width-1; j++)
		{
			for(int k=1; k<numScale-1; k++)
			{
				if((*count)>=MAXPOINTS)
				{
					for(int m=0; m<numScale; m++)
						delete[] scaledImg[m];
					delete[] scaledImg;

					return;
				}

				_point cp;
				cp.x = j;
				cp.y = i;
				float scale = minScale+k*stepScale;
				cp.radiu = int(1.414*scale+0.5);
				if(isMax(scaledImg[k-1], scaledImg[k][i*width+j], cp, 1, width, false) &&
					isMax(scaledImg[k], scaledImg[k][i*width+j], cp, 1, width, true) &&
					isMax(scaledImg[k+1], scaledImg[k][i*width+j], cp, 1, width,false))
				{
					corner[(*count)++] = cp;
					break;
				}
			}
		}
	}

	for(int i=0; i<numScale; i++)
		delete[] scaledImg[i];
	delete[] scaledImg;
}


效果图(左LOG,右DOH)

 

2015-10-23 19:15:21 lishanlu136 阅读数 6897

学习图像处理,必须首先得理解图像的特征提取,我在这里把图像的特征暂且分为如下五类:面特征、线特征、局部区域特征、点特征和不变点特征。其中,面特征对应图像多分辨率金字塔和图像的矩特征,线特征对应图像的边缘检测,局部区域特征对应图像的斑点特征检测,点特征对应图像的角点检测,不变点特征对应图像的尺度不变特征的提取。下面我一一简单说明一下这些特征。

一、图像金字塔

在数字图像处理领域,多分辨率金字塔化是图像多尺度表示的主要形式。图像金字塔化一般包括两个步骤:图像经过一个低通滤波器进行平滑;然后对这个平滑图像进行抽样,抽样比例一般在水平和垂直方向都是为1/2,从而得到一系列尺寸缩小、分辨率降低的图像。将得到的依次缩小的图像按顺序排列,看上去就像是金字塔,这就是“图像金字塔”的由来。

图像的高斯金字塔:设原图像为G0,以G0作为高斯金字塔的第0层(底层),对原始输入图像进行高斯低通滤波和隔行隔列的降采样,得到高斯金字塔的第1层;再对第1层图像低通滤波和降采样,得到高斯金字塔的第2层;重复以上过程,就可以构成高斯金字塔。可见高斯金字塔的当前层图像是对其前一层图像先进行高斯低通滤波,然后进行隔行隔列的降采样而生成的。当前层图像的大小依次为前一层图像大小的1/4。

图像的拉普拉斯金字塔:它的每一层图像是高斯金字塔本层图像与其高一级的图像(由本层图像下采样得到)经内插放大后图像的差,此过程相当于带通滤波,因此,拉普拉斯金字塔又称为带通金字塔。

MATLAB图像处理工具箱提供了impyramid()函数,用于构造图像的金字塔,其调用格式如下:B=impyramid(A,direction),该函数的功能为:对A进行高斯金字塔变换,direction为'reduce'和'expand',分别对应分解和扩张。

二、图像的矩特征

图像的矩特征是用于可以代表图像的图像描述量,不变矩(Invariant Moments,IMg)是一种高度浓缩的图像特征,具有平移、灰度、尺度、旋转不变性,因此矩和矩函数可被用于图像的模式识别、图像分类、目标识别和场景分析中。

HU矩 几何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,图像f(x,y)的(p+q)阶几何矩定义为 Mpq =∫∫(x^p)*(y^q)f(x,y)dxdy(p,q = 0,1,……∞)矩在统计学中被用来反映随机变量的分布情况,推广到力学中,它被用作刻画空间物体的质量分布。同样的道理,如果我们将图像的灰度值看作是一个二维或三维的密度分布函数,那么矩方法即可用于图像分析领域并用作图像特征的提取。最常用的,物体的零阶矩表示了图像的“质量”:Moo= ∫∫f(x,y )dxdy 一阶矩(M01,M10)用于确定图像质心( Xc,Yc):Xc = M10/M00;Yc = M01/M00;若将坐标原点移至 Xc和 Yc处,就得到了对于图像位移不变的中心矩。如Upq =∫∫[(x-Xc)^p]*[(y-Yc)^q]f(x,y)dxdy。Hu在文中提出了7个几何矩的不变量,这些不变量满足于图像平移、伸缩和旋转不变。如果定义Zpq=Upq/(U20 + U02)^(p+q+2),Hu 的7种矩为:H1=Z20+Z02;H1=(Z20+Z02)^2+4Z11^2;......

三、图像的边缘检测

图像的边缘是指其周围像素灰度急剧变化的那些像素的集合,它是图像最基本的特征。边缘存在于目标、背景和区域中,所以,它是图像分割最重要的依据。边缘检测的基本思想是先检测图像中的边缘点,再按照某种策略将边缘点连接成轮廓,从而构成分割区域。

1、运用一阶微分算子检测图像边缘

一阶微分边缘检测算子也称为梯度边缘算子,它是利用图像在边缘处的阶跃性,即图像梯度在边缘取得极大值的特性进行边缘检测。梯度是一个矢量,它具有方向和模。梯度的模值大小提供了边缘的强度信息,梯度的方向提供了边缘的趋势信息,因为梯度的方向始终是垂直于边缘的方向。在实际使用中,通常利用有限差分进行梯度近似。x方向的导数近似等于I(x+1,y)-I(x,y),y方向的导数近似等于I(x,y+1)-I(x,y),对于3*3模板中心像元的梯度,其梯度可通过下式计算得到:x方向:Mx=(a2+ca3+a4)-(a0+ca7+a6),y方向:My=(a6+ca5+a4)-(a0+ca1+a2),其中a0至a8是由模板左上角a0顺时针旋转至模板中心a8,参数c为加权系数,表示离中心像元较近。当c等于1时,就可以得到Prewitt边缘检测卷积核,当c=2时,就可以得到Sobel边缘检测卷积核。

MATLAB中也提供了相关的图像边缘检测的函数,其调用格式如下:BW = edge(I,'sobel',thresh,direction),BW = edge(I,'prewitt',thresh,direction),

BW = edge(I,'roberts',thresh),其中,I是输入的灰度图像,thresh是阈值,direction是方向。

2、傅里叶变换与图像梯度的关系

实际上,对图像进行二维傅里叶变换得到的频谱图,就是图像梯度的分布图,当然频谱图上的各点与图像上的各点并不存在一一对应的关系,在傅里叶频谱图上看到的明暗不一的亮点,实际上是图像上某一点与领域点差异的强弱,即梯度的大小,也即该点的频率大小(也可以这样理解,图像中的低频部分指低梯度的点,高频部分指高梯度的点),一般来讲,梯度大则该点的亮度强,否则该点亮度弱。通过观察图像的频谱图,我们首先可以看出图像的能量分布,如果频谱图中的暗的点数多,那么实际图像是比较柔和的(因为各点与领域差异不大,梯度相对较小),反之,如果频谱图中亮的点数较多,那么实际图像一定是尖锐的,边界分明且边界两边像素差异较大。

3、运用二阶微分算子检测图像边缘

二阶微分边缘检测算子是利用图像在边缘处的阶跃性导致图像二阶微分在边缘处出现零值这一特性进行边缘检测的,因此,该方法也被称为过零算子和拉普拉斯算子。如下:

x方向二阶微分算子=I(i,j+1)-2I(i,j)+I(i,j-1),y方向二阶微分算子=I(i+1,j)-2I(i,j)+I(i-1,j)

虽然使用二阶微分算子检测边缘的方法简单,但是它是缺点是对噪声十分敏感,同时,也不能提供边缘的方向信息。为了实现对噪声的抑制,Marr等提出了高斯拉普拉斯(LoG)的方法。即采用高斯函数作为低通滤波器对图像滤波后,再对该图像进行二阶微分运算。也可以转换为先对高斯函数进行二阶微分,然后再将结果对图像进行卷积运算。为减少高斯函数二阶微分的计算量,可以直接用高斯差分算子(Difference of Gaussian,DoG)代替它。

在MATLAB中,也提供了相关函数,其调用格式为:BW = edge(I,'log',thresh)。其中,I是输入的灰度图像,thresh是阈值。

4、基于Canny算子检测图像边缘

Canny边缘检测算子是边缘检测算子中最常用的一种,虽然Canny算子也是一阶微分算子,但它对一阶微分算子进行了扩展:主要是在原一阶微分算子的基础上,增加了非最大值抑制和双阈值两项改进。利用非最大值抑制不仅可以抑制多响应边缘,而且还可以提高边缘的定位精度;利用双阈值可以有效地减少边缘的漏检率。Canny算子进行边缘提取主要分为4步:

1)去噪声,通常使用高斯函数对图像进行平滑滤波。

2)计算梯度值与方向角。

3)非最大值抑制

4)滞后阈值化。

在MATLAB中,也提供了相关函数,其调用格式为:BW = edge(I,'canny',thresh)。其中,I是输入的灰度图像,thresh是阈值。

四、斑点特征检测

斑点通常是指与周围有着颜色和灰度差别的区域,斑点检测(Blob Detection)是数字图像处理研究的重要内容,由于斑点代表的是一个区域,相比于单纯的角点,它的稳定性要好,抗噪声能力要强。可作为局部特征中的一个重要特例,斑点在图像配准和立体视觉中充当着重要的角色。

1、利用高斯拉普拉斯(Laplace of Guassian,LoG)算子检测图像斑点是一种十分常用的方法。

注意:图像与某一个二维函数进行卷积运算,实际就是求取图像与这一函数的相似性。

2、DoH斑点

图像像素点的二阶微分Hessian矩阵的行列式DoH(Determinant of Hessian)的值同样也反映了图像局部的结构信息。它对图像中细长结构的斑点具有良好的抑制作用。

第一步:使用不同的δ生成模板,并对图像进行卷积运算;

第二步:在图像的位置空间和尺度空间搜索DoH响应的峰值。

五、角点检测

在图像中,可从两个不同的方向去定义角点:角点是两个边缘的交点;角点是领域内具有两个方向的特征点。角点所在的领域通常也是图像中稳定的、信息丰富的区域。

1、Harris角点

图像Harris角点的检测算法实现步骤归纳为:计算图像I(x,y)在x和y两个方向的梯度Ix、Iy

计算图像两个方向梯度的乘积Ix*Ix,Ix*Iy,Iy*Iy

使用高斯函数对这三个乘积进行高斯加权,生成矩阵M的元素A,B,C,其中M=[A   B

                                                                                                                                                                                                         B   C]                   

计算每个像元的Harris响应值R,并对小于某一阈值的R置零: R = { R: detM- a(tranceM)*(tranceM)< t}

在3*3或5*5的领域内进行非极大值抑制,局部极大值点即为图像中的角点。

在MATLAB中,可以调用C = cornermetric(I,‘Harris’)来检测图像的Harris角点特征,其中,I为输入的灰度图像矩阵;c为角点量度矩阵,用来探测图像中的角点信息,并与I同尺寸,C的值越大表示图像I中的像素越有可能是一个角点。

六、尺度不变特征提取

1、SIFT特征提取

尺度不变特征变换(Scale Invariant Feature Transform,SIFT)是一种图像特征提取与描述算法。SIFT算法由David.G.Lowe于1999年提出并在2004年进行了完善总结。SIFT算法可以处理两幅图像之间发生平移、旋转、尺度变化、光照变化情况下的特征匹配问题,并能在一定程度上对视角变化、仿射变化也具备较为稳定的特征匹配能力。

基本原理与具体实现步骤:

整个过程主要分为四个步骤。

(1)尺度空间峰值选择(Scale space peak selection), 这一步的目的是在尺度空间中选择选择潜在的满足尺度不变性和旋转不变性的关键点(或者称为兴趣点)。

(2)关键点定位(key point localization): 这一步的目的就是精确定位出特征关键点的位置, 涉及到剔除伪关键点。

(3)方向分配(orientation assignment): 这一步的目的就是基于关键点的局部梯度方向,给每个相应的关键点分配方向(Assign orientation to key points)。

(4)关键点描述(Key Point descriptor): 此步骤的目的就是对于每个关键点, 用一个高维度(high dimensional vector,128 维的向量)的向量去描述每个关键点。

                                                                     

图像处理--角点检测

阅读数 12584

没有更多推荐了,返回首页