Python OpenCV实现Log Gabor滤波器(由LGHD描述符扩展)_loggabor滤波器_凉公子的博客-程序员秘密

技术标签: python  图像配准  图像处理  模式识别  深度学习  opencv  

引言

笔者在研究红外图像与可见光图像配准时接触到了很多描述符,其中关于LGHD描述符的Log Gabor滤波器很有意思,与大家分享

LGHD(Log-Gabor Histogram Descriptor)

描述符的思想是基于高频分量分布的描述符对于不同的非线性强度变化具有鲁棒性。可以理解为虽然非线性强度差异可以影响图像,但是场景中所包含对象的形状的整体外观仍趋于保持恒定。Log-Gabor 滤波器是根据Gabor滤波器衍生而来,Gabor变换能达到时频局部化的目的,它能够在整体上提供信号的全部信息又能提供在任意局部时间内信号变化剧烈程度的信息。

Log-Gabor滤波器

Log-Gabor 滤波器的表达是从Gabor衍生而来的,相比于Gabor滤波器,它的传递函数是对数频率尺度下的高斯函数,始终没有直流分量,在图像处理时可以不受亮度的影响。
并经研究Log-Gabor函数更符合哺乳动物的视觉观察系统,有更优的纹理提取、目标检测效果。
Log-Gabor的传递函数为:
G ( ω ) = e − log ⁡ ( ω / ω 0 ) 2 / ( 2 ( log ⁡ ( k / ω 0 ) 2 ) ) G(\omega)=e^{-\log(\omega/\omega_0)^2/(2(\log(k/\omega_0)^2))} G(ω)=elog(ω/ω0)2/(2(log(k/ω0)2))
Log-Gabor函数并不能在空间域中得到表达式,滤波器的构造须在频域中。对图像来说,在空域的卷积等价于在频域的乘积,所以我们直接创建与图像大小相同的Log-Gabor滤波器,在频域中完成图像处理,之后再回到空域中进行统计。一个二维的Log-Gabor滤波器可以分解为径向滤波器和角度滤波器两部分,对应极坐标公式为:
Alan_Liang
完整的Log-Gabor滤波器由这两部分相乘得到:
在这里插入图片描述
其中r是经向坐标, θ \theta θ为角度坐标, f 0 , θ 0 f_0,\theta_0 f0,θ0分别为滤波器中心频率和方向角度,参数可 σ r , σ θ \sigma_r,\sigma_\theta σr,σθ分别用于决定滤波器的径向带宽和角度带宽。对提供波长的滤波器,频率由滤波器的波长设置,在不同尺度下,其转换公式为:
在这里插入图片描述
在这里我将6个方向4个尺度的Log-Gabor 滤波器做展示,滤波器与图像的大小相同,一般情况下将图像进行FFT变换后与滤波器对应位相乘,再转换至空域,就是滤波后的图像效果。

构造滤波器

import cv2
import numpy as np
import matplotlib.pyplot as plt


n_scales=4
n_angles=6
img = cv2.imread("img_path")
H,W,_ = ir_img.shape

def lowpassfilter(H, W, cutoff, n):
    if cutoff < 0 or cutoff > 0.5:
        raise ValueError('the cutoff frequency needs to be between 0 and 0.5')

    if not n == int(n) or n < 1.0:
        raise ValueError('n must be an integer >= 1')

    xrange = np.linspace(-0.5, 0.5, W)
    yrange = np.linspace(-0.5, 0.5, H)

    x, y = np.meshgrid(xrange, yrange)
    radius = np.sqrt(x ** 2 + y ** 2)
    radius = np.fft.ifftshift(radius)
    return 1.0 / (1.0 + (radius / cutoff) ** (2 * n))

xrange = np.linspace(-0.5, 0.5, W)
yrange = np.linspace(-0.5, 0.5, H)
x, y = np.meshgrid(xrange, yrange)
radius = np.sqrt(x ** 2 + y ** 2)
theta = np.arctan2(-y, x)

# numpy.fft模块中的fftshift函数可以将FFT输出中的直流分量移动到频谱的中央。ifftshift函数则是其逆操作
radius = np.fft.ifftshift(radius)
theta = np.fft.ifftshift(theta)

sintheta = np.sin(theta)
costheta = np.cos(theta)

lp_filter = lowpassfilter(H, W, 0.45, 15)
# lp_filter = np.fft.ifftshift(lp_filter)
log_gabor_filters = np.zeros((n_scales, H, W))

#  不同尺度
for sc in range(n_scales):
    wavelength = min_wavelength * multiplier ** sc
    log_gabor_filters[sc] = np.exp(
        (-(np.log(radius * wavelength + 1e-5)) ** 2) / (2 * np.log(sigma_onf + 1e-5) ** 2)) * lp_filter

spreads = np.zeros((n_angles, H, W))
#  不同方向
for o in range(n_angles):
    angle = o * np.pi / n_angles
    ds = sintheta * np.cos(angle) - costheta * np.sin(angle)
    dc = costheta * np.cos(angle) + sintheta * np.sin(angle)
    dtheta = abs(np.arctan2(ds, dc))
    dtheta = np.minimum(dtheta * n_angles * 0.5, np.pi)
    spreads[o] = (np.cos(dtheta) + 1) / 2
#  构造集合的filter
filter_bank = np.zeros((n_scales * n_angles, H, W))
for sc in range(n_scales):
    for o in range(n_angles):
        filter_bank[sc * n_angles + o] = log_gabor_filters[sc] * spreads[o]

#  可视化
for sc in range(n_scales):
    plt.figure(sc,figsize=(30,120))
    first = filter_bank[sc * n_angles] - np.min(filter_bank[sc * n_angles])
    first /= np.max(first)
    first *= 255
    shuiping = first
    for o in range(n_angles-1):
        out = filter_bank[sc * n_angles + o+1] - np.min(filter_bank[sc * n_angles + o+1])
        out /= np.max(out)
        out *= 255
        shuiping = np.hstack((shuiping,out))
        plt.imshow(shuiping,cmap="gray")

滤波器可视化

在这里插入图片描述

进行图像测试

原图
在这里插入图片描述

vi_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 图像的傅里叶变换
image_fft = cv2.dft(np.float32(vi_gray), flags=cv2.DFT_COMPLEX_OUTPUT)
eo = np.zeros((filter_bank.shape[0], filter_bank.shape[1], filter_bank.shape[2], 2))
for i, filter in enumerate(filter_bank):
    eo[i] = cv2.idft(np.multiply(np.expand_dims(filter, -1), image_fft))

for sc in range(n_scales):
    plt.figure(sc,figsize=(30,120))
    first = eo_magnitude[n_scales]
    first /= np.max(first)
    first *= 255
    shuiping = first
    for o in range(n_angles-1):
        out = eo_magnitude[sc * n_angles + o+1] - np.min(eo_magnitude[sc * n_angles + o+1])
        out /= np.max(out)
        out *= 255
        shuiping = np.hstack((shuiping,out))
        plt.imshow(shuiping,cmap="gray")

滤波后
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Find_name/article/details/120750375

智能推荐

从零开始NLP_Flyingzhan的博客-程序员秘密

从零开始NLP最近打算学习一下NLP,在这里记录一下看到的知识。1:N-gramn-gram是一种语言模型,作用就是为一句给定的单词的序列返回一个概率,表示这个序列出现的概率值。常见的有unigram,bigram,trigram等等。n个单词的句子出现的概率:unigram,假设单词之间相互独立,那么可以表示为:unigram是不可取的,因为‘i have a ...

Apache CXF - 快速指南_allway2的博客-程序员秘密

Apache CXF - 简介在当今的环境中,您可以使用多个选项来创建 Web 服务应用程序。您可以使用多种标准和广泛接受的协议中的一种或多种进行通信。例如SOAP、XML/HTTP、RESTful HTTP和CORBA(通用对象请求代理架构,在过去非常流行,但现在不常用。您还可以选择不同的传输方式,例如 HTTP、JMS、JBI和前端 API,例如JAX-RS和JAX-WS。有这么多的 Web 服务开发选项,需要一个开源服务框架来将上述所有选项粘合在一起,这就是Apache CXF所做的。在本

Spring AOP 循环应用(This means that said other beans do not use the final version of the bean..)_this means said that_普通网友的博客-程序员秘密

在做spring AOP时,总发现This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allow

从程序员到技术经理之路 1、初出茅庐_۞边城浪子的博客-程序员秘密

先自我介绍下,我是2009年毕业,大学的时候主要学习mfc,经常看侯杰深入浅出那一本书,后来毕业后找工作,第一份工作香港某汇通有限公司,刚开始的时候是股票行情数据交易,当时那一家公司只有4个技术,老大是一个c#程序员来的,我们当时的老板买来一套代码,里面的代码有8万多行,老板让我改造成港股股票软件,那时候下班经常看代码、了解iocp原理、锁、sqlserver数据存储等,花了半年基本上改造成果上线,上线后维护下服务器、客户端功能,公司的业务方向也比较小,没有一个长远的发展,当时广州某石软件也正在招聘游戏开发

&nbsp是jsp里的空格_balei2634的博客-程序员秘密

&amp;nbsp 在jsp里是空格的意思,jsp里如果用连续空格会被认为是一个,用个&amp;nbsp可以表达多少空格。转载于:https://www.cnblogs.com/youwuyi/p/10233278.html...

openlayers6【八】地图覆盖物overlay详解_ol.overlay_范特西是只猫的博客-程序员秘密

文章目录1. overlay 简述2. overlay 属性2. overlay 事件4. overlay 方法5. overlay 实例5.1 overlay 实现 windowInfo 弹窗5.2 overlay 实现 label标注信息5.3 overlay 实现 text文本信息1. overlay 简述overlay是覆盖物的意思,顾名思义就是在地图上以另外一种形式浮现在地图上,这里很多同学会跟图层layers搞混淆,主要是放置一些和地图位置相关的元素,常见的地图覆盖物为这三种类型,如:win

随便推点

error while loading shared libraries: libboost_thread.so.1.69.0: cannot open shared object file: No_fengyun_w的博客-程序员秘密

原因是自己链接的库再系统路径下找不到。解决:export LD_LIBRARY_PATH=/home/maomao/boost/lib/:$LD_LIBRARY_PATH指定路径。

CocoaPods安装和使用教程_太阳火神的美丽人生的博客-程序员秘密

CocoaPods安装和使用教程 Code4App 原创文章。转载请注明出处:http://code4app.com/article/cocoapods-install-usage目录CocoaPods是什么?如何下载和安装CocoaPods?如何使用CocoaPods? 场景1:利用CocoaPods,在项目中导入AFNetworking类库场景2:如何正确编译运行一个包含C

SAP-abap-OLE核心代码_abap ole_Qunending的博客-程序员秘密

OLE定义DATA: stexcl TYPE ole2_object, stwkli TYPE ole2_object, stappl TYPE ole2_object, stwkbk TYPE ole2_object, stacts TYPE ole2_object, stshet TYPE ole2_object, stnush TYPE ole2_object, stnunm TYPE ole2_object,

密码学简要介绍_cyf密码学_wilson_go的博客-程序员秘密

密码学中的内容十分广泛,分为公钥密码体系和对称密码体系。公钥密码体系中秘钥主要有公钥和私钥,对称密码体系没有公私钥之分。内容可以分为明文和密文。最后算法分为加密算法和解密算法。...

解决:502 bad gateway_weixin_34184561的博客-程序员秘密

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

ActiveMQ-CPP编译_weixin_30345055的博客-程序员秘密

1.activemq-cpp下载地址:http://activemq.apache.org/cms/download.html2.相关依赖库http://mirrors.hust.edu.cn/apache/apr/apr,apr-iconv,apr-util(版本号都找最高的,不要一高一低,不然编译会出问题).apr-1.5.1-win32-src.zip,apr-ico...

推荐文章

热门文章

相关标签