使用OPENCV3图像对齐

图1. 左:一幅来自Prokudin-Gorskii 的图片(未对齐);右:对齐后图像

1. 左边的图像是一个具有历史意义的照片的集合称为Prokudin-Gorskii集。图像是由使用一个早期的彩色摄像机拍摄。因为相机的机械性质,图像的颜色通道未对齐。右边的图像通过OPENCV3进行对齐后的图像。
可以从这里的下载部分中的所有示例中的所有示例代码。
在这篇文章中,我们将开始一个有趣的彩色摄影的历史。这篇文章是致力于彩色摄影的早期先驱,使我们能够捕捉和存储我们的记忆中的颜色。

2. 一个简短的彩色照片发展过程


 Maxwell 和 Sutton 拍摄的首张3灰度图像

James Clerk Maxwell在1855年提出,我们可以用滤光片(红,绿,蓝)进行滤光后拍摄,然后再将这三个图片结合起来。在1861年,英国摄影师利用这个方法拍摄了第一张彩色图像。他获取了图片的三个灰度图,然后进行了叠加。但是,这个方法存在一个问题,因为当时可用的感光材料对蓝光敏感,但对绿光不敏感,对红光几乎不敏感。虽然它的实践是革命性的,但这种方法是不实际的。

到了20世纪初,感光材料的敏感度已经大大提高,并在前十年有几种相机已经可用于彩色摄影。在这些相机,最流行的彩色相机,由Lumière 兄弟发明。

最具有竞争性的相机系统是由Adolf Miethe设计,并由Wilhelm Bermpohl制造,被称之为Professor Dr. Miethe’s Dreifarben-Camera。其中Dreifarben意为三色。同时这个相机有一个长的玻璃板,可以同时放下三色滤光片。

利用这个相机,Prokudin-Gorskii在长达十年的时间里拍摄了俄罗斯近10000张图片,幸运的,这些图片保留了下来。从这些黑白图像生成一个彩色图像是不平凡的(如图3所示)。Miethe bermpohl相机是一个机械装置,这三个图片的跨度超过2-6秒。因此,三频道经常失准,简单地堆积起来导致了一个很不理想,结果如图1所示。


OPENCV运动模块

在一个典型的图像对齐问题,一个场景我们有两个图像,他们运动模型都是相关的。不同的图像对准算法的目的是估计这些运动模型的参数,使用不同的参数和假设。一旦这些参数是已知的,就可以直接从一幅图像变换到另一个
让我们快速看看这些运动模型看起来像什么。


Translation (motion_translation):第一图像可以平移(x,y)所获得的第二图像。只有两个参数X和Y,我们需要估计。
Euclidean(motion_euclidean):第一幅图像旋转和移动版本。所以有三个参数X,Y和角度。你会注意到在图4中,当一个正方形进行欧氏变换,大小不改变,平行线保持平行,并且在变换后的直角保持不变。
Affine(motion_affine):仿射变换是一个组合的旋转,平移(移位),规模,和剪切。这个变换有六个参数。当一个正方形进行仿射变换时,平行线保持平行,但在直角相交的线不再保持正交。
单应性(motion_homography):所有上述二维变换变换。他们没有考虑到3D效果。单应变换另一方面可以考虑一些3D效果(但不是全部)。这个变换有8个参数。当一方转化使用单应能改变任何四边形。

在OpenCV的仿射变换,储存在一个2 x 3大小的矩阵。平移和欧氏变换是仿射变换的特殊情况。在平移过程中,旋转、尺度和剪切参数为零,而在欧氏变换中的尺度和剪切参数都为零。因此,移动和欧氏变换也存储在一个2×3矩阵。一旦这个矩阵估计(我们将在下一节中看到),可以对图像进行功能warpaffine。
单应性,存储在一个3×3矩阵。一旦单应估计,图像可以被纳入对齐使用warpperspective。

使用增强的相关系数图像配准(ECC)最大化

ECC的图像对准算法中引入了OpenCV 3是基于2008篇题为参量图像对齐使用增强的相关系数最大化的Georgios D. Evangelidis和Emmanouil Z. Psarakis。他们建议使用一种新的相似性度量称为增强型相关系数(ECC)的运动模型的参数估计。使用他们的方法有两个优点。

不同于像素强度差异的传统的相似性度量,ECC是光度失真的对比度和亮度不变。
虽然目标函数是参数的非线性函数,但他们发展的迭代格式来求解优化问题是线性的。换言之,他们采取了一个问题,看起来在计算复杂的表面上,并找到一个简单的方法来解决它迭代。

在OPENCV中使用findTransformECC 

在opencv中我们使用findTransformECC有以下步骤:

读取图像。
将它们转换为灰度图。
选择一个你想估计的模型。
分配空间(warp_matrix)存储运动模型。
定义一个终止准则,告诉该算法什么时候停止。
估计使用findtransformecc运动矩阵。
将经矩阵应用到图像中的一个与其他图像对齐。

// 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通道的图像,右边是调整后的图像。这张照片还显示,在第二十世纪初的照片板是敏感的,捕捉到的颜色光谱很广。鲜艳的红色,蓝色和绿色。
在前面的章节中的代码可以用来解决一个图像配准问题。然而,如果你用它来重建上述形象,你会感到非常失望。在现实世界中的计算机视觉是艰难的。
问题是,如果在一个图像中的红色,绿色和蓝色通道是不强烈相关。例如,检查出蓝色礼服的埃米尔图3穿。在三个渠道看起来有很大的不同。然而,即使强度是不同的,在三个通道中的东西是相似的,因为一个人的眼睛可以很容易地告诉它,它是相同的场景。
事实证明,在梯度域的图像的三个通道的更强烈的相关性。这并不奇怪,因为即使在三个通道中的强度可能是不同的,由对象和颜色边界所产生的边缘地图是一致的。

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; 

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);


  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值