【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 D】

2024-08-30 13:32

本文主要是介绍【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 D】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

6.4自定义角点检测

6.4.1自定义角点检测概述

前文讲解了利用Harris进行角点检测和利用Shi-Tomasi方法进行角点检测外,也可以自己制作角点检测的函数:使用cornerEigenValsAndVecs()函数和minMaxLoc()函数结合来模拟Harris角点检测,或者使用cornerMinEigenVal()函数和minMaxLoc()函数结合来模拟Shi-Tomasi角点检测,最后特征点选取的判断条件要根据实际情况进行选择。

6.4.2自定义角点检测函数

 cornerEigenValsAndVecs ()函数讲解

C++: void cornerEigenValsAndVecs(InputArray src, OutputArray dst, int blockSize, int ksize, int borderType=BORDER_DEFAULT );  

【参数】
第一个参数,src:输入单通道8-bit或者浮点类型图像。
第二个参数,dst:用来存储结果的图像,大小与输入图像一致并且为CV_32FC(6)类型。
第三个参数,blockSize:邻域大小。
第四个参数,ksize:Sobel算子当中的核大小,只能取1、3、5、7。
第五个参数,borderType:像素扩展的方法,因为在滤波处理的过程中会扩展图像边缘,每扩张一个边界像素,都需要计算出该像素点在原图中的位置,这个功能被提炼出来就变成了borderInterpolate()函数。该函数输入一个点坐标,返回他在原图中的坐标。
对于每个像素点p,该函数考虑一个blockSize*blockSize的邻域S(p),它在邻域上计算导数的协方差矩阵:
这里写图片描述
其中导数是使用Sobel()算子计算得到的。随后,函数计算矩阵M的特征值和特征向量,并将它们以(λ1, λ2, x1, y1, x2,y2)的形式存储在目标图像dst中。其中λ1, λ2是M未经过排序的特征值;x1, y1是对应于λ1的特征向量;x2, y2是对应于λ2的特征向量。该函数的输出能够用于鲁棒的边缘或角点检测。
 cornerEigenValsAndVecs ()函数源代码

/*【cornerEigenValsAndVecs ( )源代码】************************************************** @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  * @源码路径:…\opencv\sources\modules\imgproc\src\ corner.cpp* @起始行数:658行   
********************************************************************************/
void cv::cornerEigenValsAndVecs( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
{
    Mat src = _src.getMat();
    Size dsz = _dst.size();
    int dtype = _dst.type();    if( dsz.height != src.rows || dsz.width*CV_MAT_CN(dtype) != src.cols*6 || CV_MAT_DEPTH(dtype) != CV_32F )
        _dst.create( src.size(), CV_32FC(6) );
    Mat dst = _dst.getMat();
    cornerEigenValsVecs( src, dst, blockSize, ksize, EIGENVALSVECS, 0, borderType );
}

可以看出其实调用的()函数,其函数原代码如下。

/*【cornerEigenValsVecs ( )源代码】****************************************************** @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  * @源码路径:…\opencv\sources\modules\imgproc\src\ corner.cpp* @起始行数:266行   
********************************************************************************/
static void cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size,int aperture_size, int op_type, double k=0.,int borderType=BORDER_DEFAULT )
{
#ifdef HAVE_TEGRA_OPTIMIZATIONif (tegra::useTegra() && tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType))return;
#endif
#if CV_SSE2bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
#endifint depth = src.depth();double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;if( aperture_size < 0 )scale *= 2.0;if( depth == CV_8U )scale *= 255.0;scale = 1.0/scale;CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );Mat Dx, Dy;if( aperture_size > 0 ){Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType );Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType );}else{Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType );Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType );}Size size = src.size();Mat cov( size, CV_32FC3 );int i, j;for( i = 0; i < size.height; i++ ){float* cov_data = cov.ptr<float>(i);const float* dxdata = Dx.ptr<float>(i);const float* dydata = Dy.ptr<float>(i);j = 0;#if CV_NEONfor( ; j <= size.width - 4; j += 4 ){float32x4_t v_dx = vld1q_f32(dxdata + j);float32x4_t v_dy = vld1q_f32(dydata + j);float32x4x3_t v_dst;v_dst.val[0] = vmulq_f32(v_dx, v_dx);v_dst.val[1] = vmulq_f32(v_dx, v_dy);v_dst.val[2] = vmulq_f32(v_dy, v_dy);vst3q_f32(cov_data + j * 3, v_dst);}#elif CV_SSE2if (haveSSE2){for( ; j <= size.width - 8; j += 8 ){__m128 v_dx_0 = _mm_loadu_ps(dxdata + j);__m128 v_dx_1 = _mm_loadu_ps(dxdata + j + 4);__m128 v_dy_0 = _mm_loadu_ps(dydata + j);__m128 v_dy_1 = _mm_loadu_ps(dydata + j + 4);__m128 v_dx2_0 = _mm_mul_ps(v_dx_0, v_dx_0);__m128 v_dxy_0 = _mm_mul_ps(v_dx_0, v_dy_0);__m128 v_dy2_0 = _mm_mul_ps(v_dy_0, v_dy_0);__m128 v_dx2_1 = _mm_mul_ps(v_dx_1, v_dx_1);__m128 v_dxy_1 = _mm_mul_ps(v_dx_1, v_dy_1);__m128 v_dy2_1 = _mm_mul_ps(v_dy_1, v_dy_1);_mm_interleave_ps(v_dx2_0, v_dx2_1, v_dxy_0, v_dxy_1, v_dy2_0, v_dy2_1);_mm_storeu_ps(cov_data + j * 3, v_dx2_0);_mm_storeu_ps(cov_data + j * 3 + 4, v_dx2_1);_mm_storeu_ps(cov_data + j * 3 + 8, v_dxy_0);_mm_storeu_ps(cov_data + j * 3 + 12, v_dxy_1);_mm_storeu_ps(cov_data + j * 3 + 16, v_dy2_0);_mm_storeu_ps(cov_data + j * 3 + 20, v_dy2_1);}}#endiffor( ; j < size.width; j++ ){float dx = dxdata[j];float dy = dydata[j];cov_data[j*3] = dx*dx;cov_data[j*3+1] = dx*dy;cov_data[j*3+2] = dy*dy;}}boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),Point(-1,-1), false, borderType );if( op_type == MINEIGENVAL )calcMinEigenVal( cov, eigenv );else if( op_type == HARRIS )calcHarris( cov, eigenv, k );else if( op_type == EIGENVALSVECS )calcEigenValsVecs( cov, eigenv );
}

 cornerMinEigenVal ()函数讲解

C++: void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, int ksize=3, int borderType=BORDER_DEFAULT );

【参数】
第一个参数,src:输入单通道8-bit或者浮点类型图像。
第二个参数,dst:用来存储结果的图像,必须为CV_32FC1类型。
第三个参数,blockSize:邻域大小。
第四个参数,ksize:Sobel算子当中的核大小,只能取1、3、5、7。
第五个参数,borderType:像素扩展的方法,因为在滤波处理的过程中会扩展图像边缘,每扩张一个边界像素,都需要计算出该像素点在原图中的位置,这个功能被提炼出来就变成了borderInterpolate()函数。该函数输入一个点坐标,返回他在原图中的坐标。
【注】除了dst必须为CV_32FC1类型以外,其它与cornerEigenValsAndVecs()函数的一致。
 cornerMinEigenVal ()函数源代码

/*【cornerMinEigenVal ( )源代码】******************************************************* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  * @源码路径:…\opencv\sources\modules\imgproc\src\ corner.cpp* @起始行数:526行   
********************************************************************************/
void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
{CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, 0.0, borderType, MINEIGENVAL))Mat src = _src.getMat();_dst.create( src.size(), CV_32FC1 );Mat dst = _dst.getMat();
#if defined(HAVE_IPP) && (IPP_VERSION_MAJOR >= 8)CV_IPP_CHECK(){typedef IppStatus (CV_STDCALL * ippiMinEigenValGetBufferSize)(IppiSize, int, int, int*);typedef IppStatus (CV_STDCALL * ippiMinEigenVal)(const void*, int, Ipp32f*, int, IppiSize, IppiKernelType, int, int, Ipp8u*);IppiKernelType kerType;int kerSize = ksize;if (ksize < 0){kerType = ippKernelScharr;kerSize = 3;} else{kerType = ippKernelSobel;}bool isolated = (borderType & BORDER_ISOLATED) != 0;int borderTypeNI = borderType & ~BORDER_ISOLATED;if ((borderTypeNI == BORDER_REPLICATE && (!src.isSubmatrix() || isolated)) &&(kerSize == 3 || kerSize == 5) && (blockSize == 3 || blockSize == 5)){ippiMinEigenValGetBufferSize getBufferSizeFunc = 0;ippiMinEigenVal minEigenValFunc = 0;float norm_coef = 0.f;if (src.type() == CV_8UC1){getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_8u32f_C1R;minEigenValFunc = (ippiMinEigenVal) ippiMinEigenVal_8u32f_C1R;norm_coef = 1.f / 255.f;} else if (src.type() == CV_32FC1){getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_32f_C1R;minEigenValFunc = (ippiMinEigenVal) ippiMinEigenVal_32f_C1R;norm_coef = 255.f;}norm_coef = kerType == ippKernelSobel ? norm_coef : norm_coef / 2.45f;if (getBufferSizeFunc && minEigenValFunc){int bufferSize;IppiSize srcRoi = { src.cols, src.rows };IppStatus ok = getBufferSizeFunc(srcRoi, kerSize, blockSize, &bufferSize);if (ok >= 0){AutoBuffer<uchar> buffer(bufferSize);ok = minEigenValFunc(src.ptr(), (int) src.step, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi, kerType, kerSize, blockSize, buffer);CV_SUPPRESS_DEPRECATED_STARTif (ok >= 0) ok = ippiMulC_32f_C1IR(norm_coef, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi);CV_SUPPRESS_DEPRECATED_ENDif (ok >= 0){CV_IMPL_ADD(CV_IMPL_IPP);return;}}setIppErrorStatus();}}}
#endifcornerEigenValsVecs( src, dst, blockSize, ksize, MINEIGENVAL, 0, borderType );
}

可以看出也调用了cornerEigenValsVecs()函数。

6.4.3自定义角点检测实例

代码参看附件【demo1】。

这里写图片描述

图1

这里写图片描述

图2

这里写图片描述

图3

参考:
英文
中文

本章参考附件

点击进入

这篇关于【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 D】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。