一,像素重映射介绍:
简单的说就是把输入图像中各像素按照一定的规则映射到另一张图像对应的位置上去,形成一张新的图像。
g
(
x
,
y
)
g(x,y)
g(x,y) 是重映射之后的图像,
h
(
x
,
y
)
h(x,y)
h(x,y) 是功能函数,f 是源图像。
官方图例:
假设我们有一个图像
I
I
I :
h
(
x
,
y
)
=
(
I
.
c
o
l
s
−
x
,
y
)
h(x,y)=(I.cols-x,y)
h(x,y)=(I.cols−x,y)
图像会在x轴上翻转:
上图右边的是源图像,左边的是重映射后的图像。相当于镜像了一副图像,左边的到右边,右边的到左边。
二,API:
Cv2.Remap() :
参数 | 描述 |
---|---|
InputArray src | 输入源图像 |
OutputArray dst | 输出图像 |
InputArray map1 | X轴映射表:具有CV_16SC2、CV_32FC1或CV_32FC2类型的(x,y)点或x值的第一个映射。 |
InputArray map2 | Y轴映射表:具有CV_16UC1、CV_32FC1或none类型的y值的第二个映射(如果map1是(x,y)点,则为空映射)。 |
InterpolationFlags interpolation = InterpolationFlags.Linear | 插值方法(可选择,线性,双线性,立方等)。这个函数不支持INTER_AREA方法。 |
BorderTypes borderMode = BorderTypes.Constant | 边缘处理方法 |
Scalar? borderValue = null | 边缘填充的颜色 |
三,代码:
#region 像素重映射
static int index = 0;
private static void Remap(string path)
{
Mat src = new Mat(path, ImreadModes.AnyColor | ImreadModes.AnyDepth);
Mat dst = new Mat(src.Size(), src.Type());
Mat x = new Mat(src.Rows, src.Cols, MatType.CV_32FC1);
Mat y = new Mat(src.Rows, src.Cols, MatType.CV_32FC1);
new Window("Input", WindowMode.AutoSize, src);
int key = 0;
while (true)
{
key = Cv2.WaitKey(500);
index = key % 4;
if ((char)key == 27)
{
break;
}
Console.WriteLine("{0}%{1}={2}", key, 4, index);
Update_Remap(src, x, y);
Cv2.Remap(src, dst, x, y, InterpolationFlags.Linear, BorderTypes.Constant, new Scalar(0, 0, 255));
new Window("Output", WindowMode.AutoSize, dst);
}
}
private static void Update_Remap(Mat src, Mat x, Mat y)
{
for (int row = 0; row < src.Rows; row++)
{
for (int col = 0; col < src.Cols; col++)
{
switch (index)
{
case 0:
if (col > (src.Cols * 0.25) && col < (src.Cols * 0.75) && row > (src.Rows * 0.25) && row < (src.Rows * 0.75))
{
/*
* 图像的 Cols 列 组成矩阵的宽度 对应 二维平面的x轴
* 图像的 Rows 行 组成矩阵的高度 对应 二维平面的y轴
* if 条件成立必定满足
* src.Cols*0.75 <= col <= src.Cols*0.25
* src.Rows*0.75 <= row <= src.Rows*0.25
* 则:
* (col - (src.Cols * 0.25)范围在 0 -- 0.5 之间
* 若 (2 * (col - (src.Cols * 0.25)) 则:范围在 0 --1 之间 (原图像的大小)X轴
* (row - (src.Rows * 0.25))范围在 0 -- 0.5 之间
* 若 (2 * (row - (src.Rows * 0.25)) 则:范围在 0 --1 之间 (原图像的大小)Y轴
*
* 前面创建 x ,y 对象是的类型是 CV_32FC1 所以 赋值要用 float 类型
*/
float xVal = (float)(2 * (col - (src.Cols * 0.25)));
float yVal = (float)(2 * (row - (src.Rows * 0.25)));
x.Set<float>(row, col, xVal);
y.Set<float>(row, col, yVal);
}
else
{
x.Set<float>(row, col, 0);
y.Set<float>(row, col, 0);
}
break;
case 1:
x.Set<float>(row, col, (src.Cols - col - 1)); //左右映射 X 轴
y.Set<float>(row, col, row); //Y 轴不变
break;
case 2:
x.Set<float>(row, col, col); //X 轴
y.Set<float>(row, col, (src.Rows - row - 1)); //上下映射 Y轴
break;
case 3:
x.Set<float>(row, col, (src.Cols - col - 1)); //左右映射 X 轴
y.Set<float>(row, col, (src.Rows - row - 1));//上下映射 Y轴
break;
}
}
}
}
选择输出图像窗口 按 1
按2 :
按 3:
按 4: