特征提取 - 海森矩阵(Hessian Matrix)及一个用例(图像增强)

2024-03-04 13:38

本文主要是介绍特征提取 - 海森矩阵(Hessian Matrix)及一个用例(图像增强),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:https://blog.csdn.net/u013921430/article/details/79770458

这个例子效果并没有给出的结果那么好,但是Hessian矩阵的生成可以参考

前言

       Hessian Matrix(海森矩阵)在图像处理中有广泛的应用,比如边缘检测、特征点检测等。而海森矩阵本身也包含了大量的数学知识,例如泰勒展开、多元函数求导、矩阵、特征值等。写这篇博客的目的,就是想从原理和实现上讲一讲Hessian Matrix,肯定有不足的地方,希望大家批评指正。

泰勒展开及海森矩阵
      将一个一元函数f(x)在x0处进行泰勒展开,可以得到以下公式。

                                 

       其中余项为皮亚诺余项。

       其中二阶导数的部分映射到二维以及多维空间就是Hessian Matrix。在二维图像中,假设图像像素值关于坐标(x, y)的函数是f(x, y),那么将f(x+dx,y+dy)在f(x0, y0)处展开,得到如下式子

                              

     如果将这个式子用矩阵表示,并且舍去余项,则式子会是下面这个样子。

                            

      上面等式右边的第三项中的第二个矩阵就是二维空间中的海森矩阵了;从而有了一个结论,海森矩阵就是空间中一点处的二阶导数。进而推广开来,多维空间中的海森矩阵可以表示为。

                                                   

 

海森矩阵的意义

     众所周知,二阶导数表示的导数的变化规律,如果函数是一条曲线,且曲线存在二阶导数,那么二阶导数表示的是曲线的曲率,曲率越大,曲线越是弯曲。以此类推,多维空间中的一个点的二阶导数就表示该点梯度下降的快慢。以二维图像为例,一阶导数是图像灰度变化即灰度梯度,二阶导数就是灰度梯度变化程度,二阶导数越大灰度变化越不具有线性性(这里有一点绕口了,意思就是这里灰度梯度改变越大,不是线性的梯度)。

      但是在二维图像中,海森矩阵是二维正定矩阵,有两个特征值和对应的两个特征向量。两个特征值表示出了图像在两个特征向量所指方向上图像变化的各向异性。如果利用特征向量与特征值构成一个椭圆,那么这个椭圆就标注出了图像变化的各向异性。那么在二维图像中,什么样的结构最具各项同性,又是什么样的结构的各向异性更强呢?很显然,圆具有最强的各项同性,线性越强的结构越具有各向异性。如下图

                                      

注:图中箭头的方向不一定正确,我只是随意标注

       且特征值应该具有如下特性

     λ1         λ2           图像特征

-High      -High   斑点结构(前景为亮)

+High    +High   斑点结构(前景为暗)

Low        -High   线性结构(前景为亮)

Low       +High   线性结构(前景为暗) 

有一个常见的表格也把不同空间特征与特征值之间的对应关系描述的很直观

                      

 

海森矩阵的应用

       海森矩阵的应用很多,我在此不一一列举。上文中提到了矩阵的特征值与特征向量构成的椭圆表现出了图像的各向异性,这种各项异性图像处理就得到了应用。以二维图像为例,图像中的点性结构具有各项同性,而线性结构具有各向异性。因此我们可以利用海森矩阵对图像中的线性结构进行增强,滤去点状的结构和噪声点。同样,也可以用于找出图像中的点状结构,滤除其他信息。

       当然,我们在使用海森矩阵时,不需要把图像进行泰勒展开,我们只需要直接求取矩阵中的元素即可。一般,对数字图像进行二阶求导使用的是以下方法

                                     

      但是这种方法鲁棒性很差,容易受到图像中局部信号的干扰,甚至可以说,这种求导方式是存在争议的。因为这一点的二阶导数也可以采用如下方法表示;

                                     

       除了上面两种表示方法外,二阶导数还可以采用其他方式表示,而且往往不同的方法求得的值不同,因为这种方法只把包含其自身在内的三个点的信息囊括进去,信息量不足。因此,提倡大家换一种方法。根据线性尺度空间理论(LOG),对一个函数求导,等于函数与高斯函数导数的卷积。式子如下

                                                              

       由于高斯模板可以将周围一矩形范围内所有的点的信息都包含进来,这样就不会有误差。所以利用图像求取hessian矩阵中的元素时,将图像与高斯函数的二阶导数做卷积即可。在此,为大家提供高斯函数的二阶偏导。

                                                         

                                                         

      在编写程序时,我们只需要事先将图像分别于三个模板进行卷积,生成三种偏导数的“图”,然后每次根据需要索引对应位置的偏导数即可。

 

代码

        需要说明的是,我在代码中运用了一些OpenCV的函数;
 

///---------------------------///
//---海森矩阵二维图像增强
//---潘正宇---2018.03.27#include <iostream>
#include <vector>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <map>#define STEP 6
#define ABS(X) ((X)>0? X:(-(X)))
#define PI 3.1415926using namespace std;
using namespace cv;int main()
{Mat srcImage = imread("G:\\博客\\图像处理\\hessian\\hessian_matrix\\Multiscale vessel enhancement filtering1.bmp");if (srcImage.empty()){cout << "图像未被读入";system("pause");return 0;}if (srcImage.channels() != 1){cvtColor(srcImage, srcImage, CV_RGB2GRAY);}int width = srcImage.cols;int height = srcImage.rows;Mat outImage(height, width, CV_8UC1,Scalar::all(0));int W = 5;float sigma = 01;Mat xxGauKernel(2 * W + 1, 2 * W + 1, CV_32FC1, Scalar::all(0));Mat xyGauKernel(2 * W + 1, 2 * W + 1, CV_32FC1, Scalar::all(0));Mat yyGauKernel(2 * W + 1, 2 * W + 1, CV_32FC1, Scalar::all(0));//构建高斯二阶偏导数模板for (int i = -W; i <= W;i++){for (int j = -W; j <= W; j++){xxGauKernel.at<float>(i + W, j + W) = (1 - (i*i) / (sigma*sigma))*exp(-1 * (i*i + j*j) / (2 * sigma*sigma))*(-1 / (2 * PI*pow(sigma, 4)));yyGauKernel.at<float>(i + W, j + W) = (1 - (j*j) / (sigma*sigma))*exp(-1 * (i*i + j*j) / (2 * sigma*sigma))*(-1 / (2 * PI*pow(sigma, 4)));xyGauKernel.at<float>(i + W, j + W) = ((i*j))*exp(-1 * (i*i + j*j) / (2 * sigma*sigma))*(1 / (2 * PI*pow(sigma, 6)));}}for (int i = 0; i < (2 * W + 1); i++){for (int j = 0; j < (2 * W + 1); j++){cout << xxGauKernel.at<float>(i, j) << "  ";}cout << endl;}Mat xxDerivae(height, width, CV_32FC1, Scalar::all(0));Mat yyDerivae(height, width, CV_32FC1, Scalar::all(0));Mat xyDerivae(height, width, CV_32FC1, Scalar::all(0));//图像与高斯二阶偏导数模板进行卷积filter2D(srcImage, xxDerivae, xxDerivae.depth(), xxGauKernel);filter2D(srcImage, yyDerivae, yyDerivae.depth(), yyGauKernel);filter2D(srcImage, xyDerivae, xyDerivae.depth(), xyGauKernel);for (int h = 0; h < height; h++){for (int w = 0; w < width; w++){//map<int, float> best_step;/*	int HLx = h - STEP; if (HLx < 0){ HLx = 0; }int HUx = h + STEP; if (HUx >= height){ HUx = height - 1; }int WLy = w - STEP; if (WLy < 0){ WLy = 0; }int WUy = w + STEP; if (WUy >= width){ WUy = width - 1; }float fxx = srcImage.at<uchar>(h, WUy) + srcImage.at<uchar>(h, WLy) - 2 * srcImage.at<uchar>(h, w);float fyy = srcImage.at<uchar>(HLx, w) + srcImage.at<uchar>(HUx, w) - 2 * srcImage.at<uchar>(h, w);float fxy = 0.25*(srcImage.at<uchar>(HUx, WUy) + srcImage.at<uchar>(HLx, WLy) - srcImage.at<uchar>(HUx, WLy) - srcImage.at<uchar>(HLx, WUy));*/float fxx = xxDerivae.at<float>(h, w);float fyy = yyDerivae.at<float>(h, w);float fxy = xyDerivae.at<float>(h, w);float myArray[2][2] = { { fxx, fxy }, { fxy, fyy } };          //构建矩阵,求取特征值Mat Array(2, 2, CV_32FC1, myArray);Mat eValue;Mat eVector;eigen(Array, eValue, eVector);                               //矩阵是降序排列的float a1 = eValue.at<float>(0, 0);float a2 = eValue.at<float>(1, 0);if ((a1>0) && (ABS(a1)>(1+ ABS(a2))))             //根据特征向量判断线性结构{outImage.at<uchar>(h, w) =  pow((ABS(a1) - ABS(a2)), 4);//outImage.at<uchar>(h, w) = pow((ABS(a1) / ABS(a2))*(ABS(a1) - ABS(a2)), 1.5);}}}//----------做一个闭操作Mat element = getStructuringElement(MORPH_RECT, Size(3, 2));morphologyEx(outImage, outImage, MORPH_CLOSE, element);imwrite("temp.bmp", outImage);imshow("[原始图]", outImage);waitKey(0);system("pause");return 0;
}

 

输出结果

      左侧是原图,中间是增强后的结果,右侧是将增强后的结果做了二值化的结果图;

                                                                                                                            

 

结果分析

      从结果来看,图像中的大部分的线性结构都被增强了,但是有一些细微的结构并未被增强太多,而且有些粗的结构中出现了空洞,其实这都与求导窗口的大小有关,求导窗口太小,很多粗的结构会出现中空的现象,因为中心区域被认为是点结构了;求导窗口太大,就容易出现细微结构丢失的情况。此外,高斯模板的方差选取也影响了偏导数的大小。其实,这种方式是使用一个方差为s 的高斯核的二阶导数生成一个探测核,用于测量导数方向范围内(-s,s)内外区域之间的对比度。

      但是同一图像中,线性结构的粗细肯定是不同的,同样的窗口大小是无法全部适用的,针对上面的问题,有人提出了多模板的方法。即对一个点用多种尺度的高斯模板进行卷积,然后选择各向异性最强的结果作为该点的输出。值得一试。

      回过头来看,根据海森矩阵,还可以确定一张图像中的角点部分,即前面表格中提到的两个特征值的绝对值都较大的情况。其实这就是Harris 角点检测的主要思想。

最后
      这篇博客准备了一段时间了,主要是公式的原因,我想使用markdown编辑器以及LaTex公式编辑器编辑公式,但是没搞定,还需要琢磨一下,等我琢磨好了,就把这篇文章中的图片格式的公式换掉。

 

参考文献:
     Frangi A.F., Niessen W.J., Vincken K.L., Viergever M.A. (1998) Multiscale vessel enhancement filtering. In: Wells W.M., Colchester A., Delp S. (eds) Medical Image Computing and Computer-Assisted Intervention — MICCAI’98. MICCAI 1998. Lecture Notes in Computer Science, vol 1496. Springer, Berlin, Heidelberg

这篇关于特征提取 - 海森矩阵(Hessian Matrix)及一个用例(图像增强)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/773347

相关文章

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

[论文笔记]LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale

引言 今天带来第一篇量化论文LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale笔记。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 大语言模型已被广泛采用,但推理时需要大量的GPU内存。我们开发了一种Int8矩阵乘法的过程,用于Transformer中的前馈和注意力投影层,这可以将推理所需

线性代数|机器学习-P35距离矩阵和普鲁克问题

文章目录 1. 距离矩阵2. 正交普鲁克问题3. 实例说明 1. 距离矩阵 假设有三个点 x 1 , x 2 , x 3 x_1,x_2,x_3 x1​,x2​,x3​,三个点距离如下: ∣ ∣ x 1 − x 2 ∣ ∣ 2 = 1 , ∣ ∣ x 2 − x 3 ∣ ∣ 2 = 1 , ∣ ∣ x 1 − x 3 ∣ ∣ 2 = 6 \begin{equation} ||x

【LVI-SAM】激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节

激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节 1. 特征提取实现过程总结1.0 特征提取过程小结1.1 类 `FeatureExtraction` 的整体结构与作用1.2 详细特征提取的过程1. 平滑度计算(`calculateSmoothness()`)2. 标记遮挡点(`markOccludedPoints()`)3. 特征提取(`extractF

【线性代数】正定矩阵,二次型函数

本文主要介绍正定矩阵,二次型函数,及其相关的解析证明过程和各个过程的可视化几何解释(深蓝色字体)。 非常喜欢清华大学张颢老师说过的一段话:如果你不能用可视化的方式看到事情的结果,那么你就很难对这个事情有认知,认知就是直觉,解析的东西可以让你理解,但未必能让你形成直觉,因为他太反直觉了。 正定矩阵 定义 给定一个大小为 n×n 的实对称矩阵 A ,若对于任意长度为 n 的非零向量 ,有 恒成

十四、我们应当怎样做需求分析:子用例与扩展用例

用例模型作为UML中4+1视图中非常重要的一员,非常集中地体现了面向对象的分析与设计思想。用例模型将现实世界中连续的一个一个业务流程,按照场景划分到了一个一个的用例中。由于场景的出现,使得用例中的业务流程存在着高度的内聚性,从而成为了日后各种对象的雏形。同时,在用例分析中,又将那些存在于各个用例中的,相同或相近的业务操作提取出来,形成一个一个的子用例或扩展用例,又体现了面向对象设计中的复用性。现在

python科学计算:NumPy 线性代数与矩阵操作

1 NumPy 中的矩阵与数组 在 NumPy 中,矩阵实际上是一种特殊的二维数组,因此几乎所有数组的操作都可以应用到矩阵上。不过,矩阵运算与一般的数组运算存在一定的区别,尤其是在点积、乘法等操作中。 1.1 创建矩阵 矩阵可以通过 NumPy 的 array() 函数创建。矩阵的形状可以通过 shape 属性来访问。 import numpy as np# 创建一个 2x3 矩阵mat

【轻松上手postman】入门篇:如果根据接口文档写postman接口用例

在我们平时的测试工作中除了最基本的网页测试外,也会遇到没有页面但需要验证内部逻辑正确性的接口测试任务,在遇到没有网页的测试任务时,我们就要使用到接口测试工具来模拟对程序代码触发。 在接到接口测试任务时,一般都会拿到接口需求文档,没接触过接口测试的人看到接口文档正常反应一脸闷🤣不知如何下手怎么开始测试😓,下面我就来讲讲如何将接口文档上的一个个接口转换成postman用例 首先需要安装

【UVA】10003-Cutting Sticks(动态规划、矩阵链乘)

一道动态规划题,不过似乎可以用回溯水过去,回溯的话效率很烂的。 13988658 10003 Cutting Sticks Accepted C++ 1.882 2014-08-04 09:26:49 AC代码: #include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include