Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【短道速滑十一】标准的Gabor滤波器及Log_Gabor滤波器的实现、解析、速度优化及其和Halcon中gen_gabor的比较。

【短道速滑十一】标准的Gabor滤波器及Log_Gabor滤波器的实现、解析、速度优化及其和Halcon中gen_gabor的比较。

作者头像
用户1138785
发布于 2023-10-23 11:19:06
发布于 2023-10-23 11:19:06
53300
代码可运行
举报
运行总次数:0
代码可运行

  最近有朋友在研究Halcon中gen_gabor的函数,和我探讨,因为我之前也没有怎么去关注这个函数,因此,前前后后大概也折腾了有一个星期去模拟实现这个东西,虽然最终没有实现这个函数,但是也是有所收获,这里做一点总结,也算是最这个函数有个完美的收尾吧。

  1、Gabor滤波器

  首先总是度娘出场,关键词Gabor滤波器,一大堆东西出来了,里面最多的肯定是关于OpenCv的getGaborKernel函数,这个函数的具体代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 Gabor filters and such. To be greatly extended to have full texture analysis.
 For the formulas and the explanation of the parameters see:
 http://en.wikipedia.org/wiki/Gabor_filter
*/
cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta,
                            double lambd, double gamma, double psi, int ktype )
{
    double sigma_x = sigma;
    double sigma_y = sigma/gamma;
    int nstds = 3;
    int xmin, xmax, ymin, ymax;
    double c = cos(theta), s = sin(theta);
    if( ksize.width > 0 )
        xmax = ksize.width/2;
    else
        xmax = cvRound(std::max(fabs(nstds*sigma_x*c), fabs(nstds*sigma_y*s)));

    if( ksize.height > 0 )
        ymax = ksize.height/2;
    else
        ymax = cvRound(std::max(fabs(nstds*sigma_x*s), fabs(nstds*sigma_y*c)));

    xmin = -xmax;
    ymin = -ymax;
    CV_Assert( ktype == CV_32F || ktype == CV_64F );
    Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
    double scale = 1;
    double ex = -0.5/(sigma_x*sigma_x);
    double ey = -0.5/(sigma_y*sigma_y);
    double cscale = CV_PI*2/lambd;
    for( int y = ymin; y <= ymax; y++ )
        for( int x = xmin; x <= xmax; x++ )
        {
            double xr = x*c + y*s;
            double yr = -x*s + y*c;

            double v = scale*std::exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi);
            if( ktype == CV_32F )
                kernel.at<float>(ymax - y, xmax - x) = (float)v;
            else
                kernel.at<double>(ymax - y, xmax - x) = v;
        }
    return kernel;
}

  可以快速看出,这段代码仅仅是根据一些参数计算出一个卷积核,具体的公式我也没怎么关注,里面有个nstds 这个常量为3,这个只在用户输入的ksize尺寸为0的时候需要用到,感觉是和高斯核函数在半径大于3*Sigma后其对结果的贡献就可以忽略不计有关。 

  这个函数生成的卷积核的形状和参数之间的关系,很多文章都有探讨,这个不是本文的重点,比如下面这个链接:https://blog.csdn.net/Wslsdx/article/details/110728050

  基本上,在空域他的形状就是一些有间隔的白色过度条,在频域,则基本为两处白色亮点,如下图所示:

      卷积核空域图形化               对应的频域图

  通常,CV的getGaborKernel函数都要配合Filter2D函数进行卷积得到想要的结果。 

  网络上一个有意思的视觉效果方面的算法在https://zhuanlan.zhihu.com/p/584907623有提到,可以用这个滤波器来做一些特效。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static std::vector<cv::Mat> build_filters()
{
    std::vector<cv::Mat> filters;
    const int ksize = 31;
    const double sigma = 4.0;
    const double lambd = 10.0;
    const double gamma = 0.5;
    const double psi = 0;
    // 此处创建16个滤波器, 只有 getGaborkernel 的第三个参数 theta 不同
    for (int i = 0; i < 16; i++)
    {
        double theta = CV_PI * i / 16;
        cv::Mat kernel = cv::getGaborKernel(cv::Size(ksize, ksize), sigma, theta, lambd, gamma, psi, CV_32F);
        kernel /= 1.5 * cv::sum(kernel)[0];
        filters.emplace_back(kernel);
    }
    return filters;
}
cv::Mat process(const cv::Mat& src, std::vector<cv::Mat>& filters)
{
    cv::Mat accum = cv::Mat::zeros(src.size(), src.type());
    for (cv::Mat kernel: filters)
    {
        cv::Mat fimg;
        AutoTimer timer("filter2D");
        cv::filter2D(src, fimg, CV_8UC3, kernel); // 这里是耗时的瓶颈
        AutoTimer timer("getmax");
        accum = cv::max(accum, fimg);
    }
    return accum;
}
int main()
{
    cv::Mat src = cv::imread(image_path);
    std::vector<cv::Mat> filters = build_filters();
    cv::Mat res = process(src, filters);
}

 、

  这里用了16个滤波器组合求最大值,得到了一种特征线条凸出的效果。 

  当然,OpenCv的这个滤波器在一些特征识别方面也有着很大的作用,比如斑马线识别等等。

  但是,测试发现这个滤波器对参数的配置极其敏感,同一个参数,一般两个值如果只相差一点点,一般出来的效果不会有太大的区别,但是这个函数,确可能会出现极大的差异。比如波长这个参数,当为0.4和0.5的结果大相径庭。  

                波长为0.4时的结果                                                    波长为0.5时的结果

  仔细的分析这个问题,我们会发现,这个还是由于当参数改变时,这个滤波器的权重会出现波动,一般这些卷积核都需要归一化或做相关处理,当波长为0.5时,我们会发现归一化时,所有滤波器的和可能为负数或者很小的数,而为0.4时则较为正常。因此,出现了参数改变一点点,结果改变一大串的问题。

  再稍微撤远一点,当我自己实现这个函数时,我们会发现他的主要耗时还是Filter2D函数,关于这个函数,OpenCV内部是做了优化的,他会根据硬件的支持情况使用opencl/ipp等加速资源实现,速度是相当的快,而且也会对核的大小做判断,很小的核不会使用FFT。  我这里直接使用FFT做的实现,虽然我在进行FFT卷积时做了很多优化,比如拆解为多个256*256的FFT, 比如充分利用虚部的数据等等,结果还是干不过Opencv的速度。

  二、LogGabor滤波器

  拿OpenCv的Gabor滤波器和Halcon的gen_gabor相比,发现他们根本不是一回事,gen_gabor直接生成了频域的数据,而不是生成了卷积核。关于这个算子,我们发现halcon里的描述也不是特别的清晰,这有点不太像他的风格。

  百度搜索gen_gabor我们能发现的99%的资料都是halcon帮助文档的英文原版或者是相关翻译,基本没有对其进行原理进行描述。可能也是因为这个算子不是很常用的原因吧。

  在搜索Gabor滤波器时,也看到了一些文章讲LogGabor滤波器,其中有一篇文章有提到 Log-Gabor函数并不能在空间域中得到表达式,滤波器的构造须在频域中进行,这个和gen_gabor的描述非常相似。后面我们对其参数进行了一些分析,基本可以确定halcon的gabor应该是类似于LogGabor滤波器之类的。

  通过搜索LogGabor,我们得到了一下几个比较有用的参考链接和代码:

Python OpenCV实现Log Gabor滤波器(由LGHD描述符扩展) 以及 Github中一篇 PhaseCongruency/gaborconvolve.m的matlab代码

  还有一个非常有用的图片:

  通过阅读这几篇文章及其配套的代码,我们发现这个频域的滤波器可由Log-Radial Gaussian和Angular Gaussian组合而成,在Python那篇文章中,则有这更为明确的公式:

  原文描述如下:

      一个二维的L-Gaborj波器可以分解为径向滤波器和角度滤波器两部分,对应极坐标公式为:

      完整的Log-Gabor滤波器由这两部分相乘得到:

  这个公式也和上面的图片能完全对应。

  在代码实现上,我发现无损是Python的代码还是matlab的代码其实都是一个版本的,他们在计算有关的过程中都有一个lowpass的过程,我不清楚那个是目的是啥,也不知道哪里的参数来源依据是什么,但是我感觉他们不应该是我所需要的,我需要的就是上面两个公式,结合那些参考代码,我们对第一个公式(径向滤波器)的M代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WaveLength = 10;
SigmaR = 0.4;
cols = 500, rows=500;
[x,y] = meshgrid( [-cols/2:(cols/2-1)]/cols,[-rows/2:(rows/2-1)]/rows);
radius = sqrt(x.^2 + y.^2);       
Frequency = 1.0 / WaveLength;                  % 频率等于波长的导数
logGabor = exp((-(log(radius / Frequency)).^2) / (2 * SigmaR * SigmaR));  % log gabor函数的传递函数表达式
imshow(logGabor,[])

  对第二个公式的实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Angle = 45 / 180 *3.1415926;
SigmaA = 0.4;
cols = 500, rows=500;
[x,y] = meshgrid( [-cols/2:(cols/2-1)]/cols,[-rows/2:(rows/2-1)]/rows);
theta = atan2(-y,x);              
sintheta = sin(theta);
costheta = cos(theta);
ds = sintheta * cos(Angle) - costheta * sin(Angle);    
dc = costheta * cos(Angle) + sintheta * sin(Angle);     
dtheta = atan2(abs(ds),abs(dc));                           
spread = exp((-dtheta.^2) / (2 * SigmaA * SigmaA));      
imshow(spread,[])

  当将两者组合起来后,即产生如下的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WaveLength = 10;
SigmaR = 0.4;
Angle = 45 / 180 *3.1415926;
SigmaA = 0.4;
cols = 500, rows=500;
[x,y] = meshgrid( [-cols/2:(cols/2-1)]/cols,[-rows/2:(rows/2-1)]/rows);
radius = sqrt(x.^2 + y.^2);  
Frequency = 1.0 / WaveLength;                  % 频率等于波长的导数
logGabor = exp((-(log(radius / Frequency)).^2) / (2 * SigmaR * SigmaR));  % log gabor函数的传递函数表达式
theta = atan2(-y,x);              
sintheta = sin(theta);
costheta = cos(theta);
ds = sintheta * cos(Angle) - costheta * sin(Angle);    
dc = costheta * cos(Angle) + sintheta * sin(Angle);     
dtheta = atan2(abs(ds),abs(dc));                           
spread = exp((-dtheta.^2) / (2 * SigmaA * SigmaA));      
imshow(logGabor .* spread,[])

  三段代码产生的图像依次如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                                        WaveLength = 10,SigmaR = 0.4,Angle = 45 / 180 *3.1415926, SigmaA = 0.4;

  通过改变参数可以获得不同的效果,比如,WaveLength = 5,SigmaR = 0.05,Angle = 30 / 180 *3.1415926, SigmaA = 0.3时的效果如下:

  注意到,相比于原始的代码,我们在计算dtheta时,稍微做了修改,这是因为,频域的数据一般是要求堆成的,而原始的角向滤波器是非对称的,因此,我们改成了atan2(abs(ds),abs(dc));

  这个生成的过程里有很多浮点的计算,而且有几个复杂度比较高的函数,因此,计算还是有所耗时的。 

  我们来和halcon的gen_gabor的参数做下比较:

        gen_gabor( : ImageFilter : Angle, Frequency, Bandwidth, Orientation, Norm, Mode, Width, Height : )

  后面Norm, Mode, Width, Height 这四个参数不用管它,我们主要看看前面四个参数。 

  注意到我们刚才的代码里也提供了四个可选的参数,即WaveLength,SigmaR,Angle, SigmaA,那他们之间有么有什么对应的关系呢。 

  通过多次比较和测试,我们可以定性的确定如下联系:

  1、gen_gabor里的Orientation和我的LogGabor里的Angle基本是一个意思,这个可以从Orientation的范围可以看到,就是个角度范围:

     Orientation (input_control) real → (real)         Angle of the principal orientation,Suggested values: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.14

    2、gen_gabor的Bandwidth和LogGabor的SigmaR的趋势基本是一致的。

       3、gen_gabor的Frequency和LogGabor的WaveLength的趋势基本是相反的,但是WaveLength本身就是Frenquency的倒数,都是会随着Frequency的变小,频域的有效部分想中心收缩。

       4、gen_gabor的Angle和LogGabor的SigmaA的趋势基本是相反的。

  也就是说这4个参数基本上都存在一一对应的关系,只是说我们无法确认他们之间的绝对值之间的联系,毕竟halcon里也没有提供具体的计算式,只要稍微某个地方有些取值不同,就会造成不同的结果。 

  由于loggabor提供的已经是频域的数据了,因此,后续的计算就比较简单了,因为频域的乘法就相当于于时域的卷积,因此,直接把某个图像的频域数据乘以这个LogGabor数据就可以了。

       但是,这就要求LogGabor的数据维度必须和图像是一样大小的,其实这个有个隐藏的问题,即边缘问题,因为卷积对于边缘一般来说是需要扩展的,否则会遇到一些小小意料之外的问题。 

  做了一个简单的比较,当gen_gabor和LogGabor滤波器的可视化图基本类似时,大部分情况两者之间的效果似乎方向是一致的。 

            halcon的gen_gabor可视化结果                                      对应的滤波器输出

     LogGabor参数                            LogGabor可视化结果                            对应的滤波器结果

  上述结果的halcon代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
read_image (Image, 'fabrik')
get_image_size (Image, Width, Height)
gen_gabor(Filter,10,0.1,50,1.57,'n','dc_center',Width, Height)
fft_generic(Image,ImageFFT,'to_freq',-1,'none','dc_center','complex')
convol_gabor(ImageFFT,Filter,Gabor,Hilbert)
fft_generic(Gabor,GaborInv,'from_freq',1,'none','dc_center','byte')

  可以看出,两者的结果存在一定的相似性,从某个侧面说明我们的猜测具有一定的科学性。

  三、速度优化

  从上面的过程可以看到我们的LogGabor滤波器的生成有着较为复杂的计算公式,而且有多个函数调用,这些函数其实都是有着较为复杂的内部计算的,要进行优化,可以从多方面出发,第一个是用C语言处理吧,把一些公共的计算放到循环外部,把能优化掉的除法尽量改为乘法,还可以把那个exp的计算合并为一个,因为我们知道exp(a) * exp(b) = exp(a+b),这样就可以减少一次exp计算了。

  当然,我们还可以进行指令集优化,我们可以自定义_mm_atan2_ps, _mm_sincos_ps, _mm_exp_ps等等指令集函数(网络上可以找到的),他们可以接受成吨的输出。很爽,至少速度比C版本的提高3到4倍。

  我们在计算频域相乘时,也可以适当的考虑扩大图像,让图像的尺寸变为那些更有利于做FFT变换的数据,比如4、5、8的倍数等等,这样,可以有效地提高FFT的运算速度,并且对结果只会造成轻微的影响。

  关于这个算法目前就研究这么多吧,希望能造福有需要的人,也能造福自己。

  此更新算法位于我的SSE Demo的如下目录:   Detection(检测相关)---》Gabor Filter(Gabor滤波)。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OpenCV Gabor滤波器实现纹理提取与缺陷分析
Gabor滤波器是OpenCV中非常强大一种滤波器,广泛应用在纹理分割、对象检测、图像分维、文档分析、边缘检测、生物特征识别、图像编码与内容描述等方面。Gabor在空间域可以看做是一个特定频率与方向的正弦平面加上一个应用在正弦平面波上的高斯核
OpenCV学堂
2018/07/26
7.4K1
OpenCV Gabor滤波器实现纹理提取与缺陷分析
Gabor 滤波
https://developer-public-1258344699.cos.ap-guangzhou.myqcloud.com/column/column/10335061/20230218-68017941.png
为为为什么
2023/02/18
1.1K0
Gabor 滤波
python实现gabor滤波器提取纹理特征 提取指静脉纹理特征 指静脉切割代码
参考博客:https://blog.csdn.net/xue_wenyuan/article/details/51533953 https://blog.csdn.net/jinshengtao/article/details/17797641 傅里叶变换是一种信号处理中的有力工具,可以帮助我们将图像从空域转换到频域,并提取到空域上不易提取的特征。但是经过傅里叶变换后,   图像在不同位置的频度特征往往混合在一起,但是Gabor滤波器却可以抽取空间局部频度特征,是一种有效的纹理检测工具。 在图像处理中,G
徐飞机
2018/06/21
2.4K0
手撕OpenCV源码之高斯模糊
从上述代码的大致分析中可以知道,OpenCV的GaussianBlur本质上依然是filter2D,只是针对一些特殊情况进行了GPU和CPU版本的优化,如果输入的维度等信息不满足这些特殊情况,则选择使用filter2D进行计算.关于优化不是本文的重点,filter2D会在后续的博文中进行详细分析,所以这里只对获取GaussianKernel的部分进行介绍.
OpenCV学堂
2018/07/26
2.5K0
【OpenCV】Chapter6.频率域图像滤波
OpenCV 中的cv.dft()函数也可以实现图像的傅里叶变换,cv.idft()函数实现图像傅里叶逆变换。
zstar
2022/09/26
1.6K0
【OpenCV】Chapter6.频率域图像滤波
从傅立叶变换到Gabor滤波器
作者:夏 敏 编辑:李文臣 PART 01 gabor介绍 gabor特征 首先我们介绍下Gabor 特征,它是一种可以用来描述图像纹理信息的特征,Gabor 滤波器的频率和方向与人类的视觉系统类似,特别适合于纹理表示与判别。它主要依靠 Gabor 核在频率域上对信号进行加窗,从而能描述信号的局部频率信息。 而Gabor 核靠傅里叶变换,我们才能将信号转换到频率域,才能让Gabor核在频率域去加窗。而在原本的空间域中,一个 Gabor 核实际上就是一个高斯核与正弦波调制的结果,可以看做是高斯核应用在了正弦
机器学习算法工程师
2018/03/06
2.2K0
从傅立叶变换到Gabor滤波器
python实现gabor滤波器提取纹理特征 提取指静脉纹理特征 指静脉切割代码
参考博客: https://blog.csdn.net/xue_wenyuan/article/details/51533953 https://blog.csdn.net/jinshengtao/article/details/17797641 傅里叶变换是一种信号处理中的有力工具,可以帮助我们将图像从空域转换到频域,并提取到空域上不易提取的特征。但是经过傅里叶变换后,   图像在不同位置的频度特征往往混合在一起,但是Gabor滤波器却可以抽取空间局部频度特征,是一种有效的纹理检测工具。 在图像处理中
徐飞机
2018/05/15
2.9K0
基于粒子滤波的物体跟踪
一直都觉得粒子滤波是个挺牛的东西,每次试图看文献都被复杂的数学符号搞得看不下去。一个偶然的机会发现了Rob Hess(http://web.engr.oregonstate.edu/~hess/)实现的这个粒子滤波。从代码入手,一下子就明白了粒子滤波的原理。根据维基百科上对粒子滤波的介绍(http://en.wikipedia.org/wiki/Particle_filter),粒子滤波其实有很多变种,Rob Hess实现的这种应该是最基本的一种,Sampling Importance Resampling (SIR),根据重要性重采样。下面是我对粒子滤波实现物体跟踪的算法原理的粗浅理解:
MachineLP
2022/05/09
6690
基于粒子滤波的物体跟踪
自动驾驶定位算法(十三)-粒子滤波(Particle Filter)
自动驾驶对定位的精度的要求在厘米级的,如何实现厘米级的高精度定位呢?一种众所周知的定位方法是利用全球定位系统(GPS),利用多颗卫星的测量结果,通过三角测量(Triangulation)机制确定目标的位置,GPS定位的原理见自动驾驶硬件系统(十一)-Global Navigation Satellite Systems (GNSS),但是GPS并不总是提供高精度定位数据,在GPS信号强的情况下,定位精度在1~3m范围内,在GPS信号弱的情况下,定位精度下降到10~50m范围内。虽然依赖于RTK,可以将卫星定位的精度提高到厘米级,但是在GPS信号弱的场景下,定位精度仍然不能满足应用需求。所以仅仅使用GPS不能实现高可靠的高精度定位的。
YoungTimes
2022/04/28
2.8K0
自动驾驶定位算法(十三)-粒子滤波(Particle Filter)
关于粒子滤波的解析
基本原理:随机选取预测域的 N NN 个点,称为粒子。以此计算出预测值,并算出在测量域的概率,即权重,加权平均就是最优估计。之后按权重比例,重采样,进行下次迭代。
芯动大师
2024/09/11
1360
关于粒子滤波的解析
综述:图像滤波常用算法实现及原理解析
来源丨https://zhuanlan.zhihu.com/p/279602383
计算机视觉
2021/01/12
1.9K0
综述:图像滤波常用算法实现及原理解析
南开提出全新ViT | Focal ViT融会贯通Gabor滤波器,实现ResNet18相同参数,精度超8.6%
自从Vision Transformer(ViT)的开创性工作以来,视觉 Transformer 在诸如图像分类、目标检测和语义分割等各种计算机视觉任务中取得了令人瞩目的进展。它们为这些任务提供了新的模式和解决方案,同时打破了卷积神经网络(CNNs)在计算机视觉领域的垄断。普遍认为,自注意力是 Transformer 成功的关键。这种注意力机制能够同时建模输入序列中不同位置之间的关系,在全局特征交互和长距离依赖提取方面表现出色。
集智书童公众号
2024/02/21
7800
南开提出全新ViT | Focal ViT融会贯通Gabor滤波器,实现ResNet18相同参数,精度超8.6%
Canny算法解析,opencv源码实现及实例[通俗易懂]
Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。
全栈程序员站长
2022/09/02
2.4K0
javaweb(四)——过滤器与监听器
了解滤波器的定义、分类和工作原理等基本概念。 滤波器(Filter)是信号处理领域中的一个重要概念,可以将输入信号按照一定的规则进行处理,以获得期望的输出信号。滤波器广泛应用于通信、音频、视频等领域。
一只
2024/06/26
2170
javaweb(四)——过滤器与监听器
图像处理-图像增强
图像增强是图像模式识别中非常重要的图像预处理过程。 图像增强的目的是通过对图像中的信息进行处理,使得有利于模式识别的信息得到增强,不利于模式识别的信息被抑制,扩大图像中不同物体特征之间的差别,为图像的信息提取及其识别奠定良好的基础。图像增强按实现方法不同可分为点增强、空域增强和频域增强。
AomanHao
2022/01/14
6K1
图像处理-图像增强
关键点检测项目代码开源了!
本文通过自建手势数据集,利用YOLOv5s检测,然后通过开源数据集训练squeezenet进行手部关键点预测,最后通过指间的夹角算法来判断具体的手势,并显示出来。文章第四部分为用C++实现整体的ncnn推理(代码较长,可先马后看)
Datawhale
2022/02/17
7730
关键点检测项目代码开源了!
Opencv 源码初探
序言 这篇博客主要是想记录一下关于 opencv 这个库的一些学习心得,并穿插一些图像处理的基本知识。 分析基于 opencv 4.5.1,其他版本可能会存在一些接口的变动,还请注意。 准备 首先是 opencv 的安装。对于 python 版的 opencv,可以直接使用 pip install 进行安装。对于 C++ 版则可以自己下载源码进行编译与安装。这里介绍在 ubuntu 下如何编译源码:
苏州程序大白
2021/08/13
2.9K0
Opencv 源码初探
opencv常用函数
本文主要介绍:Opencv常用函数,如均值、最大最小、归一化、滤波、旋转、求连通域等函数。
vv彭
2020/12/16
1.1K0
NumPyML 源码解析(四)
The wrappers.py module implements wrappers for the layers in layers.py. It includes
ApacheCN_飞龙
2024/02/17
3830
机器学习-09-图像处理02-PIL+numpy+OpenCV实践
开源地理空间基金会中文分会 Pillow (PIL Fork) 10.0.1 文档
用户2225445
2024/04/14
6060
机器学习-09-图像处理02-PIL+numpy+OpenCV实践
相关推荐
OpenCV Gabor滤波器实现纹理提取与缺陷分析
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验