您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

OpenCV(C++/Python)中的图像对齐(ECC)

5b51 2022/1/14 8:19:00 python 字数 11490 阅读 440 来源 www.jb51.cc/python

OpenCV(C++/Python)中的图像对齐(ECC)图1左图:ProkudinGorskii收藏的图片。右:通道对齐的同一图像??左边的这张照片是名为普罗库丁-戈尔斯基(Prokudin-Gorskii)的历史照片集的一部分。这张照片是一位俄罗斯摄影师在20世纪初用早期的彩色相机拍摄的。由于相机的机械特性,

概述

图1。左图:Prokudin Gorskii收藏的图片。右:通道对齐的同一图像

??左边的这张照片是名为普罗库丁-戈尔斯基(Prokudin-Gorskii)的历史照片集的一部分。这张照片是一位俄罗斯摄影师在20世纪初用早期的彩色相机拍摄的。由于相机的机械特性,图像的颜色通道未对齐。右侧的图像是同一个图像使用OpenCV 3中提供的功能使通道对齐之后的版本。

OpenCV中的运动模型

??在一个典型的图像对齐问题中,我们有一个场景的两幅图像,它们通过一个运动模型相关联。不同的图像对齐算法使用不同的技巧和假设来估计这些运动模型的参数。一旦知道了这些参数,就可以直接对一张图像进行扭曲,使其与另一张图像对齐。让我们快速看看这些运动模型是什么样子的。

在这里插入图片描述

?? 在OpenCV中,仿射变换存储在2x3大小的矩阵中。平移变换和欧氏变换是仿射变换的特例。在平移变换中,旋转、缩放和剪切参数为零,而在欧几里得变换中,缩放和剪切参数为零。因此,平移和欧几里得变换也存储在2x3矩阵中。一旦估计出这个矩阵(我们将在下一节中看到),就可以使用warpAffine函数使图像对齐。而单应性变换存储在3 × 3矩阵中。一旦对单应性进行了估计,就可以使用warpPerspective函数对图像进行对齐。

基于增强型相关系数(ECC)最大化的图像配准

??OpenCV 3中引入的ECC图像对齐算法基于2008年Georgios D.Evangelidis和Emmanouil Z.PSarakis发表的一篇题为《 Parametric Image Alignment using Enhanced Correlation
Coefficient Maximization》的论文。他们建议使用一种名为增强相关系数(ECC)的新相似性度量来估计运动模型的参数。他们的方法有两个优点。

1. 与传统的像素亮度差异相似性度量不同,ECC在对比度和亮度上不受光度失真的影响。
2. 虽然目标函数是参数的非线性函数,但他们提出的求解优化问题的迭代格式是线性的。换句话说,他们把一个表面上看起来计算成本很高的问题,找到了一种更简单的迭代求解方法

OpenCV中的findTransformECC示例

??在OpenCV 3中,使用函数findTransformECC估计ECC图像对齐的运动模型。以下是使用findTransformECC的步骤

??让我们深入研究代码,看看如何使用它。

C++代码

// Read the images to be aligned
Mat im1 = imread("images/image1.jpg");
Mat im2 = imread("images/image2.jpg");

// Convert images to gray scale;
Mat im1_gray, im2_gray;
cvtColor(im1, im1_gray, CV_BGR2GRAY);
cvtColor(im2, im2_gray, CV_BGR2GRAY);

// Define the motion model
const int warp_mode = MOTION_EUCLIDEAN;

// Set a 2x3 or 3x3 warp matrix depending on the motion model.
Mat warp_matrix;

// Initialize the matrix to identity
if ( warp_mode == MOTION_HOMOGRAPHY )
    warp_matrix = Mat::eye(3, 3, CV_32F);
else
    warp_matrix = Mat::eye(2, 3, CV_32F);

// Specify the number of iterations.
int number_of_iterations = 5000;

// Specify the threshold of the increment
// in the correlation coefficient between two iterations
double termination_eps = 1e-10;

// Define termination criteria
TermCriteria criteria (TermCriteria::COUNT+TermCriteria::EPS, number_of_iterations, termination_eps);

// Run the ECC algorithm. The results are stored in warp_matrix.
findTransformECC(
                 im1_gray,
                 im2_gray,
                 warp_matrix,
                 warp_mode,
                 criteria
             );

// Storage for warped image.
Mat im2_aligned;

if (warp_mode != MOTION_HOMOGRAPHY)
    // Use warpAffine for Translation, Euclidean and Affine
    warpAffine(im2, im2_aligned, warp_matrix, im1.size(), INTER_LINEAR + WARP_INVERSE_MAP);
else
    // Use warpPerspective for Homography
    warpPerspective (im2, im2_aligned, warp_matrix, im1.size(),INTER_LINEAR + WARP_INVERSE_MAP);

// Show final result
imshow("Image 1", im1);
imshow("Image 2", im2);
imshow("Image 2 Aligned", im2_aligned);
waitKey(0);

重建Prokudin-Gorskii彩色藏品

在这里插入图片描述

??上图也是普罗库丁-戈尔斯基收藏的一部分。左侧是未对齐RGB通道的图像,右侧是对齐后的图像。这张照片还表明,到了20世纪初,照相底片已经足够灵敏,能够漂亮地捕捉到广泛的彩色光谱。鲜艳的红色、蓝色和绿色令人惊叹。

??前一节的代码可以用来解决一个简单的问题。然而,如果你用它来重建上面的图像,你会非常失望。现实世界中的计算机视觉是困难的,事情往往不是真的开箱即用。

??问题是,图像中的红色、绿色和蓝色通道在像素强度方面的相关性并不像您可能猜测的那样强。然而,尽管强度不同,但这三个通道中的一些东西是相似的,因为人眼很容易分辨出这是同一个场景。结果表明,图像的三个通道在梯度域中的相关性更强。这并不奇怪,因为尽管三个通道中的强度可能不同,但由对象和颜色边界生成的边缘贴图是一致的。

??下面给出图像梯度的近似值

C++代码

using namespace cv;
using namespace std;

Mat GetGradient(Mat src_gray)
{
  
  Mat grad_x, grad_y;
  Mat abs_grad_x, abs_grad_y;
  
  int scale = 1;
  int delta = 0;
  int ddepth = CV_32FC1; ;

  // Calculate the x and y gradients using Sobel operator
  Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
  convertScaleAbs( grad_x, abs_grad_x );

  Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
  convertScaleAbs( grad_y, abs_grad_y );
  
  // Combine the two gradients
  Mat grad;
  addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );

  return grad; 

}

??现在我们准备重建彩色图片!请阅读下面的内联注释

C++代码

 

using namespace cv;
using namespace std;

// Read 8-bit color image.
// This is an image in which the three channels are
// concatenated vertically.
Mat im =  imread("images/emir.jpg", IMREAD_GRAYSCALE);

// Find the width and height of the color image
Size sz = im.size();
int height = sz.height / 3;
int width = sz.width; 

// Extract the three channels from the gray scale image
vector<Mat>channels;
channels.push_back(im( Rect(0, 0,         width, height)));
channels.push_back(im( Rect(0, height,    width, height)));
channels.push_back(im( Rect(0, 2*height,  width, height))); 

// Merge the three channels into one color image
Mat im_color;
merge(channels,im_color);

// Set space for aligned image.
vector<Mat> aligned_channels;
aligned_channels.push_back(Mat(height, width, CV_8UC1));
aligned_channels.push_back(Mat(height, width, CV_8UC1));

// The blue and green channels will be aligned to the red channel.
// So copy the red channel
aligned_channels.push_back(channels[2].clone());

// Define motion model
const int warp_mode = MOTION_AFFINE;

// Set space for warp matrix.
Mat warp_matrix;

// Set the warp matrix to identity.
if ( warp_mode == MOTION_HOMOGRAPHY )
    warp_matrix = Mat::eye(3, 3, CV_32F);
else
    warp_matrix = Mat::eye(2, 3, CV_32F);

// Set the stopping criteria for the algorithm.
int number_of_iterations = 5000;
double termination_eps = 1e-10;

TermCriteria criteria(TermCriteria::COUNT+TermCriteria::EPS,
                          number_of_iterations, termination_eps);

// Warp the blue and green channels to the red channel
for ( int i = 0; i < 2; i++)
{
  
   double cc = findTransformECC (
                   GetGradient(channels[2]),
                   GetGradient(channels[i]),
                   warp_matrix,
                   warp_mode,
                   criteria
               );

   if (warp_mode == MOTION_HOMOGRAPHY)
     // Use Perspective warp when the transformation is a Homography
     warpPerspective (channels[i], aligned_channels[i], warp_matrix, aligned_channels[0].size(), INTER_LINEAR + WARP_INVERSE_MAP);
   else
      // Use Affine warp when the transformation is not a Homography
      warpAffine(channels[i], aligned_channels[i], warp_matrix, aligned_channels[0].size(), INTER_LINEAR + WARP_INVERSE_MAP);

} 

// Merge the three channels
Mat im_aligned;
merge(aligned_channels, im_aligned);

// Show final output
imshow("Color Image", im_color);
imshow("Aligned Image", im_aligned);
waitKey(0);

进一步改进

??如果您要真正制作一个商业图像配准产品,您需要做的工作要比我的代码所做的多得多。例如,当不对齐很大时,此代码可能会失败。在这种情况下,需要在较低分辨率版本的图像上估计扭曲参数,并使用在低分辨率版本中估计的参数初始化较高分辨率版本的扭曲矩阵。此外,findTransformECC估计单个全局变换以进行对齐。当图像中存在局部运动(例如,被摄体在两张照片中略有移动)时,该运动模型显然是不合适的。在这种情况下,需要使用例如基于光流的方法进行附加的局部对准。

转载翻译自下面的链接:https://learnopencv.com/image-alignment-ecc-in-opencv-c-python/

(https://learnopencv.com/image-alignment-ecc-in-opencv-c-python/)

总结

以上是编程之家为你收集整理的OpenCV(C++/Python)中的图像对齐(ECC)全部内容,希望文章能够帮你解决OpenCV(C++/Python)中的图像对齐(ECC)所遇到的程序开发问题。


如果您也喜欢它,动动您的小指点个赞吧

除非注明,文章均由 laddyq.com 整理发布,欢迎转载。

转载请注明:
链接:http://laddyq.com
来源:laddyq.com
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


联系我
置顶