- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
细化角点的位置。
 该函数迭代以找到角点或径向鞍点的亚像素级准确位置,如 93中所述,并如下图所示。
 
 亚像素级准确的角点定位器基于这样一个观察:从中心点 q 到位于 q 的邻域内的某个点 p 的每一个向量都垂直于 p 处的图像梯度,前提是图像和测量噪声的影响。考虑以下表达式:
  
      
       
        
         
         
           ϵ 
          
         
           i 
          
         
        
          = 
         
         
          
          
            D 
           
           
           
             I 
            
            
            
              p 
             
            
              i 
             
            
           
          
         
           T 
          
         
        
          ⋅ 
         
        
          ( 
         
        
          q 
         
        
          − 
         
         
         
           p 
          
         
           i 
          
         
        
          ) 
         
        
       
         \epsilon _i = {DI_{p_i}}^T \cdot (q - p_i) 
        
       
     ϵi=DIpiT⋅(q−pi)
 其中  
     
      
       
       
         D 
        
        
        
          I 
         
         
         
           p 
          
         
           i 
          
         
        
       
      
        {DI_{p_i}} 
       
      
    DIpi 是邻域中某一点  
     
      
       
        
        
          p 
         
        
          i 
         
        
       
      
        p_i 
       
      
    pi处的图像梯度。需要找到 q 的值,使得  
     
      
       
        
        
          ϵ 
         
        
          i 
         
        
       
      
        \epsilon_i 
       
      
    ϵi 最小化。可以建立一个方程组,将  
     
      
       
        
        
          ϵ 
         
        
          i 
         
        
       
      
        \epsilon_i 
       
      
    ϵi设为零:
 
      
       
        
         
         
           ∑ 
          
         
           i 
          
         
        
          ( 
         
        
          D 
         
         
         
           I 
          
          
          
            p 
           
          
            i 
           
          
         
        
          ⋅ 
         
         
          
          
            D 
           
           
           
             I 
            
            
            
              p 
             
            
              i 
             
            
           
          
         
           T 
          
         
        
          ) 
         
        
          ⋅ 
         
        
          q 
         
        
          − 
         
         
         
           ∑ 
          
         
           i 
          
         
        
          ( 
         
        
          D 
         
         
         
           I 
          
          
          
            p 
           
          
            i 
           
          
         
        
          ⋅ 
         
         
          
          
            D 
           
           
           
             I 
            
            
            
              p 
             
            
              i 
             
            
           
          
         
           T 
          
         
        
          ⋅ 
         
         
         
           p 
          
         
           i 
          
         
        
          ) 
         
        
       
         \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) \cdot q - \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i) 
        
       
     i∑(DIpi⋅DIpiT)⋅q−i∑(DIpi⋅DIpiT⋅pi)
 其中梯度是在 q 的邻域(“搜索窗口”)内求和。称第一个梯度项为 G,第二个梯度项为 b,则有:
  
      
       
        
        
          q 
         
        
          = 
         
         
         
           G 
          
          
          
            − 
           
          
            1 
           
          
         
        
          ⋅ 
         
        
          b 
         
        
       
         q = G^{-1} \cdot b 
        
       
     q=G−1⋅b
 算法将邻域窗口的中心设置在这个新的中心 q 上,然后迭代直到中心保持在一个设定的阈值内。
函数原型
void cv::cornerSubPix	
(
	InputArray 	image,
	InputOutputArray 	corners,
	Size 	winSize,
	Size 	zeroZone,
    TermCriteria 	criteria 
)		
参数
-  参数image 输入单通道 8 位或浮点图像。 
-  参数corners 输入角点的初始坐标,并提供输出精炼后的坐标。 
-  参数winSize 搜索窗口边长的一半。例如,如果 winSize = Size(5, 5),则使用 (52+1)×(52+1) = 11×11 的搜索窗口。 
-  参数zeroZone 搜索区域内中间死区大小的一半,在该区域内公式下的求和不做。有时用于避免自相关矩阵可能的奇异情况。值 (-1, -1) 表示没有这样的大小。 
-  参数criteria 迭代过程角点精炼的终止标准。也就是说,角点位置精炼的过程在达到 criteria.maxCount 次迭代或在某次迭代中角点位置移动小于 criteria.epsilon 时停止。 
代码示例
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
    // 加载图像
    cv::Mat img = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/hawk.jpg", cv::IMREAD_GRAYSCALE );
    if ( img.empty() )
    {
        std::cout << "Error opening image" << std::endl;
        return -1;
    }
    // 检测角点
    std::vector< cv::Point2f > corners;
    cv::goodFeaturesToTrack( img, corners, 100, 0.01, 10, cv::Mat() );
    // 设置搜索窗口大小
    cv::Size win( 5, 5 );
    // 设置零区间大小
    cv::Size zeroZone( -1, -1 );
    // 设置终止标准
    cv::TermCriteria criteria( cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.01 );
    // 对角点进行亚像素级别的精炼
    cv::cornerSubPix( img, corners, win, zeroZone, criteria );
    // 在原始图像上标记精炼后的角点
    cv::Mat imgColor;
    cv::cvtColor( img, imgColor, cv::COLOR_GRAY2BGR );
    for ( const auto& corner : corners )
    {
        cv::circle( imgColor, corner, 2, cv::Scalar( 0, 0, 255 ), 2 );  // 画红色圆圈
    }
    // 显示标记角点的图像
    cv::imshow( "Original Image", img );
    cv::imshow( "Refined Corners", imgColor );
    cv::waitKey( 0 );
    return 0;
}
运行结果



![[Unity Demo]从零开始制作空洞骑士Hollow Knight第六集:制作小骑士完整的跳跃落地行为](https://i-blog.csdnimg.cn/direct/6e7912ad92324467872b2f8e8ea196f1.png)
















