harris corner detector java实现

/**

 * Millie : Multifunctional Library For Image Processing

 * 

 * (c) Copyright 2009 by Humbert Florent

 * 

 *      This program is free software; you can redistribute it and/or modify  

 *      it under the terms of the GNU General Public License as published by  

 *      the Free Software Foundation; only version 2 of the License.          

 *                                                                            

 *      This program is distributed in the hope that it will be useful,       

 *      but WITHOUT ANY WARRANTY; without even the implied warranty of        

 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         

 *      GNU General Public License for more details.                          

 *                                                                            

 *      You should have received a copy of the GNU General Public License     

 *      along with this program; if not, write to the Free Software           

 *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA             

 *      02111-1307, USA.                                                      

 */

package millie.operator.detection;


import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;


import millie.image.Image;

import millie.operator.commons.component.ComponentSeparableOp;


/**

 * Harris Corner Detector

 * 

 *  k = det(A) - lambda * trace(A)^2

 * 

 *  Where A is the second-moment matrix 

 * 

 *            | Lx(x+dx,y+dy)    Lx.Ly(x+dx,y+dy) |

 *  A =  Sum  |                                    | * Gaussian(dx,dy)

 *      dx,dy | Lx.Ly(x+dx,y+dy)  Ly(x+dx,y+dy)   |

 * 

 *  and lambda = 0.06  (totaly empirical :-)

 *  

 *  

 * @author Xavier Philippeau

 */

public class HarrisFastDetectionOperator extends ComponentSeparableOp {


// image info

int width,height;

// precomputed values of the derivatives

private double[][] Lx2,Ly2,Lxy;


// private class that represents a corner

private class Corner {

int x,y;

double measure;

public Corner(int x, int y, double measure) {

this.x = x;

this.y = y;

this.measure = measure;

}

}

// list of corners

private List<List<Corner>> allCorners;

// corner filtering

private int radius = 0;

private double gaussiansigma = 0;

private int minDistance = 0;

private int minMeasure = 0;

public HarrisFastDetectionOperator(int radius, double gaussiansigma, int minMeasure, int minDistance) {

this.radius = radius;

this.gaussiansigma = gaussiansigma;

this.minDistance = minDistance;

this.minMeasure = minMeasure;

}

public void setup(Image in, int canal) {

allCorners = new ArrayList<List<Corner>>();

for(int i=0; i<canal; i++)

allCorners.add(new ArrayList<Corner>());

}

@Override

public void computeComponent(Image out, Image in, int canal) {

filter(out, in, canal);

}


private List<Corner> getCorner(int canal) {

return allCorners.get(canal);

}


/**

* Gaussian function

*/

private double gaussian(double x, double y, double sigma2) {

double t = (x*x+y*y)/(2*sigma2);

double u = 1.0/(2*Math.PI*sigma2);

double e = u*Math.exp( -t );

return e;

}

/**

* Sobel gradient 3x3

*/

private double[] sobel(Image image, int canal, int x, int y) {

int v00=0,v01=0,v02=0,v10=0,v12=0,v20=0,v21=0,v22=0;

int x0 = x-1, x1 = x, x2 = x+1;

int y0 = y-1, y1 = y, y2 = y+1;

if (x0<0) x0=0;

if (y0<0) y0=0;

if (x2>=width) x2=width-1;

if (y2>=height) y2=height-1;

v00=(int)getInsidePixel(image, x0, y0, canal);

v10=(int)getInsidePixel(image, x1, y0, canal);

v20=(int)getInsidePixel(image, x2, y0, canal);

v01=(int)getInsidePixel(image, x0, y1, canal);

v21=(int)getInsidePixel(image, x2, y1, canal);

v02=(int)getInsidePixel(image, x0, y2, canal);

v12=(int)getInsidePixel(image, x1, y2, canal);

v22=(int)getInsidePixel(image, x2, y2, canal);

double sx = (v20+2*v21+v22)-(v00+2*v01+v02);

double sy = (v02+2*v12+v22)-(v00+2*v10+v20);

return new double[] {sx/4,sy/4};

}

 

/**

* Compute the 3 arrays Ix, Iy and Ixy

*/

private void computeDerivatives(Image image, int canal, int radius, double sigma){

this.Lx2 = new double[width][height];

this.Ly2 = new double[width][height];

this.Lxy = new double[width][height];

 

// gradient values: Gx,Gy

double[][][] grad = new double[width][height][];

for (int y=0; y<this.height; y++)

for (int x=0; x<this.width; x++)

grad[x][y]= sobel(image, canal, x, y);

// precompute the coefficients of the gaussian filter 

double[][] filter = new double[2*radius+1][2*radius+1];

double filtersum = 0;

for(int j=-radius;j<=radius;j++) {

for(int i=-radius;i<=radius;i++) {

double g = gaussian(i,j,sigma);

filter[i+radius][j+radius]=g;

filtersum+=g;

}

}

// Convolve gradient with gaussian filter:

//

// Ix2 = (F) * (Gx^2)

// Iy2 = (F) * (Gy^2)

// Ixy = (F) * (Gx.Gy)

//

for (int y=0; y<this.height; y++) {

for (int x=0; x<this.width; x++) {

for(int dy=-radius;dy<=radius;dy++) {

for(int dx=-radius;dx<=radius;dx++) {

int xk = x + dx;

int yk = y + dy;

if (xk<0 || xk>=this.width) continue;

if (yk<0 || yk>=this.height) continue;

// filter weight

double f = filter[dx+radius][dy+radius];

// convolution

this.Lx2[x][y]+=f*grad[xk][yk][0]*grad[xk][yk][0];

this.Ly2[x][y]+=f*grad[xk][yk][1]*grad[xk][yk][1];

this.Lxy[x][y]+=f*grad[xk][yk][0]*grad[xk][yk][1];

}

}

this.Lx2[x][y]/=filtersum;

this.Ly2[x][y]/=filtersum;

this.Lxy[x][y]/=filtersum;

}

}

}

/**

* compute harris measure for a pixel

*/

private double harrisMeasure(int x, int y) {

// matrix elements (normalized)

double m00 = this.Lx2[x][y]; 

double m01 = this.Lxy[x][y];

double m10 = this.Lxy[x][y];

double m11 = this.Ly2[x][y];

// Harris corner measure = det(M)-lambda.trace(M)^2

 

return m00*m11 - m01*m10 - 0.06*(m00+m11)*(m00+m11);

}

/**

* return true if the measure at pixel (x,y) is a local spatial Maxima

*/

private boolean isSpatialMaxima(double[][] hmap, int x, int y) {

int n=8;

int[] dx = new int[] {-1,0,1,1,1,0,-1,-1};

int[] dy = new int[] {-1,-1,-1,0,1,1,1,0};

double w =  hmap[x][y];

for(int i=0;i<n;i++) {

double wk = hmap[x+dx[i]][y+dy[i]];

if (wk>=w) return false;

}

return true;

}

/**

* compute the Harris measure for each pixel of the image

*/

private double[][] computeHarrisMap() {

 

// Harris measure map

double[][] harrismap = new double[width][height];

double max=0;

// for each pixel in the image

for (int y=0; y<this.height; y++) {

for (int x=0; x<this.width; x++) {

// compute ans store the harris measure

harrismap[x][y]=harrisMeasure(x,y);

if (harrismap[x][y]>max) max=harrismap[x][y];

}

}


// rescale measures in 0-100

for (int y=0; y<this.height; y++) {

for (int x=0; x<this.width; x++) {

double h=harrismap[x][y];

if (h<0) h=0; else h = 100 * Math.log(1+h) / Math.log(1+max);

harrismap[x][y]=h;

}

}

return harrismap;

}

/**

* Perfom Harris Corner Detection

*/

public void filter(Image output, Image input, int canal) {

this.width = input.getWidth();

this.height = input.getHeight();

 

// precompute derivatives

computeDerivatives(input, canal, this.radius, this.gaussiansigma);

// Harris measure map

double[][] harrismap = computeHarrisMap();

// copy of the original image (a little darker)

output.resize(this.width, this.height); 

for (int y=0; y<this.height; y++)

for (int x=0; x<this.width; x++)

setInsidePixel(output, x,y, canal, (int)(getInsidePixel(input, x,y, canal)*0.80));


// for each pixel in the hmap, keep the local maxima

for (int y=1; y<this.height-1; y++) {

for (int x=1; x<this.width-1; x++) {

double h = harrismap[x][y];

if (h<this.minMeasure) continue;

if (!isSpatialMaxima(harrismap, (int)x, (int)y)) continue;

// add the corner to the list

getCorner(canal).add( new Corner(x,y,h) );

}

}

// remove corners to close to each other (keep the highest measure)

Iterator<Corner> iter = getCorner(canal).iterator();

while(iter.hasNext()) {

Corner p = iter.next();

for(Corner n:getCorner(canal)) {

if (n==p) continue;

int dist = (int)Math.sqrt( (p.x-n.x)*(p.x-n.x)+(p.y-n.y)*(p.y-n.y) );

if( dist>this.minDistance) continue;

if (n.measure<p.measure) continue;

iter.remove();

break;

}

}

// Display corners over the image (cross)

for (Corner p:getCorner(canal)) {

for (int dx=-2; dx<=2; dx++) {

if (p.x+dx<0 || p.x+dx>=width) continue;

setInsidePixel(output, (int)p.x+dx, (int)p.y, canal, 255);

}

for (int dy=-2; dy<=2; dy++) {

if (p.y+dy<0 || p.y+dy>=height) continue;

setInsidePixel(output, (int)p.x,(int)p.y+dy, canal, 255);

}

}

}

float getInsidePixel(Image c, int x, int y, int canal) {

if(x<0||y<0||x>=c.getWidth()||y>=c.getHeight()) return 0;

return c.getPixel(x, y, canal);

}

void setInsidePixel(Image c, int x, int y, int canal, float value) {

if(x<0||y<0||x>=c.getWidth()||y>=c.getHeight()) return;

c.setPixel(x,y, canal, value);

}



}

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角点检测的结果是灰度图,图中的值为角点检测的打分值。需要选取合适的阈值对结果进行二值化来检测角点。
### 回答1: Harris 角点检测器是一种计算机视觉算法,用于检测图像中的角点。它是由 Chris Harris 和 Mike Stephens 在 1988 年提出的。该算法通过计算图像中每个像素的灰度值的变化率来检测角点。如果一个像素的灰度值在不同方向上的变化率都很大,那么它就很可能是一个角点。Harris 角点检测器在计算机视觉中被广泛应用,例如在图像配准、目标跟踪和三维重建等领域。 ### 回答2: Harris角点检测器是一种在计算机视觉中常用的特征提取方法,由Chris Harris和Mike Stephens在1988年提出。其主要用于角点检测,即在图像中寻找具有局部最大变化的像素点,通常被视为图像中的特殊点。 Harris角点检测器的核心思想是通过对窗口内的像素灰度值进行变换(如Sobel算子),得到该窗口中像素点的梯度和方向。然后,利用这些梯度和方向信息来计算每个像素点的角点响应值,该值将显示角点的强度。 计算角点响应值时,Harris采用了二次方程模型,其公式为:R=det(M)-k*(tr(M))^2,其中M是一个2x2的矩阵,用来描述像素点附近的图像局部结构。det(M)表示M的行列式,tr(M)表示M的迹,k是一个常数,用于调整角点响应值的相对重要性。 若M的两个特征值都很大,则表示像素点临近区域内的灰度值变化很强,是角点。若一个特征值很大,而另一个特征值很小,则表示该像素点所在区域是边缘。若两个特征值都很小,则表示该像素点所在区域是灰度值均匀的区域,不是特殊点。 一旦计算出每个像素点的角点响应值,便可通过一个阈值来筛选出真正的角点。一般而言,角点响应值大于某个设定阈值的像素点才被认定为角点。 总的来说,Harris角点检测器是一种简单有效的特征提取方法,具有不受缩放旋转变换影响、对噪声具有一定鲁棒性等优点。因此,它在计算机视觉中得到广泛应用,如图像识别、目标跟踪等领域。 ### 回答3: Harris角点检测器是一种常见的计算机视觉算法,用于检测图像中的角点特征。角点是指在图像中发生了明显变化的像素位置,这些像素通常是物体边界的交点或者拐角位置。由于角点在不同图像中往往是唯一的,因此角点特征很适合用于计算机视觉领域的目标识别、跟踪、拼接等任务。 Harris角点检测器是由Chris Harris和Mike Stephens在1988年提出的。这种方法通过计算图像中每个像素周围一定范围内像素值的方差和协方差矩阵来判断每个像素是否为角点。基本思路是:如果某个像素周围的像素都是相似的,则该像素可能是平坦区域或者边缘,而不是角点;如果某个像素周围的像素在不同方向上都有差异,则该像素可能是角点。 Harris角点检测器的具体算法步骤如下: 1. 计算每个像素点周围一定范围内像素值的梯度和方向。 2. 计算每个像素点的协方差矩阵,即对于一个像素点(x, y),其协方差矩阵为: ![image.png](attachment:image.png) 其中,Ix和Iy分别是x和y方向的梯度值。 3. 对于每个像素点,计算其响应函数R,即: ![image-2.png](attachment:image-2.png) 其中,k是一个常数,一般取较小的值,如0.04。 4. 针对每个像素点的R值,通过阈值筛选出角点。 5. 对于可能产生误检测的情况,可以通过非极大值抑制和距离筛选等方法进行更进一步的优化。 总体来说,Harris角点检测器是一种简单但有效的特征提取方法,在计算机视觉、图像处理等领域得到了广泛应用。此外,针对不同的任务和应用场景,还有许多基于Harris角点检测器的改进算法,如SIFT、SURF和FAST等,都在一定程度上提高了角点特征的稳定性和鲁棒性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值