openCV2马拉松第18圈——坐标变换

计算机视觉讨论群162501053
转载请注明:http://blog.csdn.net/abcd1992719g


收入囊中
  • 仿射变换
  • 坐标映射
  • 利用坐标映射做一些效果,例如以下
openCV2马拉松第18圈——坐标变换上面是原图,以下是利用坐标映射后的结果
该问题来自于http://zhidao.baidu.com/link?

url=OvyNHG3WKjwxbiJDOWund5lfoAPXkxXdzSyFcQqI3NKsJZkqOZjlPegJ4DG75vOosupgaM3iklTPnq3TSzHnZq



葵花宝典
先说一下什么是仿射变换

平移是最简单的变换
缩放也比較简单
翻转也非经常见
旋转也能够通过旋转矩阵表示
错切,指的是类似于四边形不稳定性那种性质,街边小商店那种铁拉门都见过吧?想象一下上面铁条构成的菱形拉动的过程。那就是“错切”的过程
仿射是这5种操作的组合,保持了平行性,给定仿射矩阵,能够非常easy的变换坐标。原坐标乘变换矩阵就能够得到新的坐标。

详细原理:http://baike.baidu.com/view/954621.htm?

fr=aladdin


那么我们怎么进行仿射变换呢?
我们知道仿射变换描写叙述了两张图片的关系。我们的任务就是找出仿射变换的矩阵。

我们仅仅要知道3个相应点,就能知道这个矩阵。OpenCV提供了这样一个计算的函数

getAffineTransform

openCV2马拉松第18圈——坐标变换

Image1中的点1。2,3相应到了Image2中的点1,2。3。这样我们就能得到仿射矩阵。于是Image1中的全部点都能通过这个仿射矩阵映射到Image2中

openCV2马拉松第18圈——坐标变换

仿射变换后

openCV2马拉松第18圈——坐标变换
坐标映射
最简单的坐标映射是一一相应,可是事情非常多时候不是这种。

在做图像增强时。我们改变的时图像的值域,g(x)output   f(x)是input   h是我们的方法,比方对照度增强直方图均衡化      用g(x) = h(f(x)) 

可是在坐标变换,改变的是定义域, g(x) = f(h(x)) 

openCV2马拉松第18圈——坐标变换

如果我们有源图像f和坐标映射函数h,我们要怎么计算输出图像g呢?

大部分人都会这样

procedure forwardWarp(f,h,outg):

For every pixelxinf(x)

1. Compute the destination locationx=h(x).

2. Copy the pixelf(x)tog(x)

我一開始也是这样想的。那就是遍历源图像,对一个Point p,应用变换函数h计算其在输出图像的坐标P',然后复制
这样的想法非常自然,仅仅只是有非常多缺陷。最最主要的一个问题就是映射出来的非常少是整数,会引来一系列问题。造成比方一个非常大的空洞等等。
因此。我们应该採用

procedure inverseWarp(f,h,outg):

For every pixelxing(x)

1. Compute the source locationx=hˆ(x)
2. Resamplef(x)at locationx and copy tog(x

遍历输出图像的点。映射到源图像,再去取点。

映射函数h就是原来h的逆矩阵。

当然了,也会碰到非整数的情况,接下来还要作一些别的处理。就不细述。


另一种简单的坐标映射,就是人工指定了输出图像的哪个点相应到源图像的哪个点。在OpenCV里叫remapping
openCV2马拉松第18圈——坐标变换

一眼就能看出。我们的映射函数是openCV2马拉松第18圈——坐标变换

openCV2马拉松第18圈——坐标变换



初识API


C++: void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
 
  • src – 输入图像
  • dst – 输出图像。有dsize的大小(由于仿射会把图片变大变小),type和src一样
  • M – openCV2马拉松第18圈——坐标变换 仿射矩阵.
  • dsize – 输出图像的大小.
  • flags –WARP_INVERSE_MAP意味着M是逆变换 ( openCV2马拉松第18圈——坐标变换 ).
  • borderMode .
  • borderValue 默认是0.

获得我们的变换矩阵M

   /// 设置源图像和相应图像的3组相应点
   srcTri[0] = Point2f( 0,0 );
   srcTri[1] = Point2f( src.cols - 1, 0 );
   srcTri[2] = Point2f( 0, src.rows - 1 );

   dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
   dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
   dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );
   /// 获得变换矩阵
   warp_mat = getAffineTransform( srcTri, dstTri );

附上官方的sample




怎样实现openCV2马拉松第18圈——坐标变换这种变换呢

for( int j = 0; j < src.rows; j++ ) {
    for( int i = 0; i < src.cols; i++ ) {
        map_x.at<float>(j,i) = src.cols - i ;
        map_y.at<float>(j,i) = j ; }}
然后再调用

remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );

remap很好懂,INTER_LINEAR是线性插值

以下是官方的sample,比較简单就不解释啦



荷枪实弹
remap还有很多其它的功能,比方能帮我们实现图像的缩放,k是缩放系数


举一反三
openCV2马拉松第18圈——坐标变换我们一開始就见到了这图片,那么怎么实现呢?
我在y轴事实上没有缩放。仅仅在x轴进行了缩放。分别分成了三段。


我的程序首先要用户在图片上点两次,各自是要扩大的举行的左上角和右下角。
然后,就以左上角的x和右下角的x为界。分为3段进行映射。