本文主要讲解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使用特定映射转换原图像
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:
|
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 | |
BORDER_REPLICATE | |
BORDER_REFLECT | |
BORDER_WRAP | |
BORDER_REFLECT_101 | |
BORDER_TRANSPARENT | |
BORDER_REFLECT101 | same as BORDER_REFLECT_101 |
BORDER_DEFAULT | same as BORDER_REFLECT_101 |
BORDER_ISOLATED | do not look outside of ROI |
把一个图像中一个位置的像素放置到另一个图片指定位置的过程.
为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.
我们通过重映射来表达每个像素的位置 :
这里 是目标图像, 是源图像, 是作用于 的映射方法函数.
让我们来思考一个快速的例子. 想象一下我们有一个图像 , 我们想满足下面的条件作重映射:
会发生什么? 图像会按照 轴方向发生翻转. 例如, 源图像如下:
看到红色圈关于 x 的位置改变( 轴水平翻转):
#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
map_y.at
}
else
{
map_x.at
map_y.at
}
}
}
}
void update_map1(void)
{
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
map_x.at
map_y.at
}
}
}
void update_map2(void)
{
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
map_x.at
map_y.at
}
}
}
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
map_y.at
}
}
}
这里只需要简单的说明一下map_x和map_y。//加0.5是为了四舍五入。
下面的代码片段说明上述的映射过程. 在这里 map_x 代表第一个坐标 h(i,j) , map_y 是第二个坐标.