opencv中关于重映射和仿射变换

opencv中关于重映射和仿射变换_第1张图片本文主要讲解opencv中重映射变换和放射变换。包括remap函数、getAffineTransform 函数、warpAffine 函数、getRotationMatrix2D 函数。


1、remap函数     

C++: voidremap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, intborderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

Applies a generic geometrical transformation to an image.     //对图像进行简单的几何变换

The function remap transforms the source image using the specified map:    //函数remap使用特定映射转换原图像

dst(x,y)=src(mapx(x,y),mapy(x,y))
Parameters
src Source image.
dst Destination image. It has the same size as map1 and the same type as src .
map1 The first map of either (x,y) points or just x values having the type CV_16SC2 , CV_32FC1, or CV_32FC2. See convertMaps for details on converting a floating point representation to fixed-point for speed.
map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map if map1 is (x,y) points), respectively.
interpolation Interpolation method (see cv::InterpolationFlags). The method INTER_AREA is not supported by this function.
borderMode Pixel extrapolation method (see cv::BorderTypes). When borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image that corresponds to the "outliers" in the source image are not modified by the function.
borderValue Value used in case of a constant border. By default, it is 0.

interpolation:插值方法

enum   cv::InterpolationFlags { 
  cv::INTER_NEAREST = 0, 
  cv::INTER_LINEAR = 1, 
  cv::INTER_CUBIC = 2, 
  cv::INTER_AREA = 3, 
  cv::INTER_LANCZOS4 = 4, 
  cv::INTER_MAX = 7, 
  cv::WARP_FILL_OUTLIERS = 8, 
  cv::WARP_INVERSE_MAP = 16 
}


INTER_NEAREST 

nearest neighbor interpolation     //邻近插值

INTER_LINEAR 

bilinear interpolation     //双线性插值

INTER_CUBIC 

bicubic interpolation    //双立方插值

INTER_AREA 

resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.

使用像素区域关系的重采样。它可能是一个图像抽取的首选方法,因为它给了moire'-free 结果。但是当图像被放大,它类似于inter_nearest方法。 

INTER_LANCZOS4 

Lanczos interpolation over 8x8 neighborhood

Lanczos 8邻域插值 

INTER_MAX 

mask for interpolation codes

用于内插码的掩模

WARP_FILL_OUTLIERS 

flag, fills all of the destination image pixels. If some of them correspond to outliers in the source image, they are set to zero

标记,填充所有目标图像像素。如果其中一些对应于源图像中的异常值,它们将被设置为零            

WARP_INVERSE_MAP 

flag, inverse transformation

For example, polar transforms:

  • flag is not set: dst(ϕ,ρ)=src(x,y)
  • flag is set: dst(x,y)=src(ϕ,ρ)


enum   cv::BorderTypes { 
  cv::BORDER_CONSTANT = 0, 
  cv::BORDER_REPLICATE = 1, 
  cv::BORDER_REFLECT = 2, 
  cv::BORDER_WRAP = 3, 
  cv::BORDER_REFLECT_101 = 4, 
  cv::BORDER_TRANSPARENT = 5, 
  cv::BORDER_REFLECT101 = BORDER_REFLECT_101, 
  cv::BORDER_DEFAULT = BORDER_REFLECT_101, 
  cv::BORDER_ISOLATED = 16 
}

borderMode的取值值如下:例如borderMode取值1(BORDER_REPLICATE) 时,边界填充值取图像的最边界值。

Enumerator
BORDER_CONSTANT 

iiiiii|abcdefgh|iiiiiii with some specified i

BORDER_REPLICATE 

aaaaaa|abcdefgh|hhhhhhh

BORDER_REFLECT 

fedcba|abcdefgh|hgfedcb

BORDER_WRAP 

cdefgh|abcdefgh|abcdefg

BORDER_REFLECT_101 

gfedcb|abcdefgh|gfedcba

BORDER_TRANSPARENT 

uvwxyz|absdefgh|ijklmno

BORDER_REFLECT101 

same as BORDER_REFLECT_101

BORDER_DEFAULT 

same as BORDER_REFLECT_101

BORDER_ISOLATED 

do not look outside of ROI

重映射是什么意思?

  • 把一个图像中一个位置的像素放置到另一个图片指定位置的过程.

  • 为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.

  • 我们通过重映射来表达每个像素的位置 (x,y) :

    g(x,y) = f ( h(x,y) )

    这里 g() 是目标图像, f() 是源图像, h(x,y) 是作用于 (x,y) 的映射方法函数.

  • 让我们来思考一个快速的例子. 想象一下我们有一个图像 I , 我们想满足下面的条件作重映射:

    h(x,y) = (I.cols - x, y )

    会发生什么? 图像会按照 x 轴方向发生翻转. 例如, 源图像如下:

    opencv中关于重映射和仿射变换_第2张图片


  • 看到红色圈关于 x 的位置改变( x 轴水平翻转):

    opencv中关于重映射和仿射变换_第3张图片




#include
#include
#include

using namespace cv;
using namespace std;

Mat src, dst;
Mat map_x, map_y;
char* remap_window = "Remap";

void update_map0(void);
void update_map1(void);
void update_map2(void);
void update_map3(void);

int main(void)
{
/// Load the image
src = imread("1.jpg", 1);


/// Create dst, map_x and map_y with the same size as src:
dst.create(src.size(), src.type());
map_x.create(src.size(), CV_32FC1);
map_y.create(src.size(), CV_32FC1);
imshow("1", src);
/// Create window
namedWindow(remap_window, CV_WINDOW_AUTOSIZE);


while (true)
{
/// Each 1 sec. Press ESC to exit the program
int c = waitKey(1000);

if ((char)c == 27)
{
break;
}
//按下a图像变为原来的1/2
if ((char)c == 'a') {
update_map0();
}
       //按下b图像上下翻转
if ((char)c == 'b') {
update_map1();
}
//按下c图像左右翻转
if ((char)c == 'c') {
update_map2();
}
//按下d图像上下左右翻转
if ((char)c == 'd') {
update_map3();
}
remap(src, dst, map_x, map_y, 0, BORDER_CONSTANT, Scalar(0, 0, 0));

/// Display results
imshow(remap_window, dst);
}
return 0;
}
void update_map0(void)
{
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75)
{
map_x.at(j, i) = 2*(i - src.cols*0.25) + 0.5;
map_y.at(j, i) = 2*(j - src.rows*0.25) + 0.5;
}
else
{
map_x.at(j, i) =0;
map_y.at(j, i) =0;
}
}
}
}

void update_map1(void)
{
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
map_x.at(j, i) = i;
map_y.at(j, i) = src.rows - j;
}
}
}

void update_map2(void)
{
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
map_x.at(j, i) = src.cols - i;
map_y.at(j, i) = j;
}
}
}

void update_map3(void)
{
ind = 0;


for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
map_x.at(j, i) = src.cols - i;
map_y.at(j, i) = src.rows - j;
}
}
}


这里只需要简单的说明一下map_x和map_y。//加0.5是为了四舍五入。

  1. 更新重映射矩阵: 我们将分别使用4种不同的映射:

    1. 图像宽高缩小一半,并显示在中间:

      h(i,j) = ( 2*i - src.cols/2  + 0.5, 2*j - src.rows/2  + 0.5)

      所有成对的参数 (i,j) 处理后都符合: \dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4} 和 \dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}

    2. 图像上下颠倒: h( i, j ) = (i, src.rows - j)

    3. 图像左右颠倒: h(i,j) = ( src.cols - i, j )

    4. 同时执行b和c的操作: h(i,j) = ( src.cols - i, src.rows - j )

下面的代码片段说明上述的映射过程. 在这里 map_x 代表第一个坐标 h(i,j) , map_y 是第二个坐标.


opencv中关于重映射和仿射变换_第4张图片


opencv中关于重映射和仿射变换_第5张图片


opencv中关于重映射和仿射变换_第6张图片


opencv中关于重映射和仿射变换_第7张图片


opencv中关于重映射和仿射变换_第8张图片






你可能感兴趣的:(Opencv3.0学习)