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

# LoG检测

ddt[h(t)f(t)]=ddtf(τ)ddth(tτ)dτ=f(t)ddth(t)$\frac{d}{dt}[h(t)\ast f(t)]=\frac{d}{dt}\int f(\tau)\frac{d}{dt}h(t-\tau)d\tau = f(t)\ast \frac{d}{dt}h(t)$，在求一次到顺序就变回来了;

Δ2normg=σ2(2gx2+2gy2)=σ2Δ2g$\Delta_{norm}^2 g=\sigma^2(\frac{\partial^2 g}{\partial x^2}+\frac{\partial^2 g}{\partial y^2})=\sigma^2 \Delta^2 g$
Δ2normg$\Delta_{norm}^2 g$的极值点，等价于求取下式：(Δ2normg)σ=0$\frac{\partial {(\Delta_{norm}^2 g)}}{\partial \sigma}=0$
(x2+y22σ2)ex2+y22σ2$(x^2+y^2-2\sigma^2)e^{-\frac{x^2+y^2}{2\sigma^2}}$
r22σ2=0$r^2-2\sigma^2=0$

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

## LOG斑点检测

$$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)$$

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


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

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

## 1. 原理

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

(1)LOG

(2)DOH

LOG斑点检测算法步骤：

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

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

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

## 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;
}

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

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

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、运用一阶微分算子检测图像边缘

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)

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

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

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

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

3）非最大值抑制

4）滞后阈值化。

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

2、DoH斑点

1、Harris角点

B   C]

1、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 维的向量）的向量去描述每个关键点。