从Halcon算子到线性代数:手把手教你用3x3矩阵搞定图像平移旋转(附完整代码)
·
从Halcon算子到线性代数:手把手教你用3x3矩阵搞定图像平移旋转(附完整代码)
在计算机视觉领域,图像变换是最基础也最核心的操作之一。无论是工业检测中的零件定位,还是自动驾驶中的场景理解,都离不开对图像进行平移、旋转等几何变换。Halcon作为业界领先的机器视觉软件,提供了丰富的算子来实现这些功能。但知其然更要知其所以然,本文将带你深入理解这些算子背后的数学原理,并用线性代数中的3x3矩阵手动实现相同的功能。
1. 图像变换的数学基础
1.1 齐次坐标:让平移也能用矩阵表示
在二维空间中,一个点的坐标通常表示为(x,y)。但如果只用这样的二维向量,平移操作就无法用矩阵乘法来表示。这就是引入齐次坐标的原因。
齐次坐标通过在二维坐标后添加一个额外的维度(通常设为1),将点表示为(x,y,1)。这样,所有常见的几何变换都可以统一用3x3矩阵来表示:
-
平移矩阵:
[1, 0, tx] [0, 1, ty] [0, 0, 1 ]其中tx和ty分别表示x和y方向的平移量
-
旋转矩阵:
[cosθ, -sinθ, 0] [sinθ, cosθ, 0] [ 0, 0, 1]θ表示旋转角度,逆时针方向为正
1.2 变换矩阵的构成原理
理解变换矩阵的关键在于分析矩阵的每一部分如何影响坐标:
- 左上2x2子矩阵控制线性变换(旋转、缩放、剪切)
- 第三列的前两行控制平移
- 最后一行保持为[0,0,1]以保证齐次坐标性质
这种表示方法的优势在于可以将多个变换通过矩阵乘法组合起来。例如,先旋转再平移的操作可以表示为:
T = 平移矩阵 × 旋转矩阵
2. Halcon中的矩阵操作函数
2.1 创建和操作矩阵
Halcon提供了一系列矩阵操作函数,让我们能够直接使用这些数学原理:
* 创建3x3单位矩阵
create_matrix(3, 3, [1,0,0, 0,1,0, 0,0,1], MatrixID)
* 矩阵相乘
mult_matrix(MatrixA, MatrixB, 'AB', ResultMatrix)
* 矩阵求逆
invert_matrix(MatrixID, 'general', 0, InverseMatrix)
2.2 与标准算子的对应关系
Halcon的几何变换算子实际上都是在内部构建并应用了相应的变换矩阵:
| 算子 | 等效矩阵操作 |
|---|---|
hom_mat2d_translate |
创建平移矩阵 |
hom_mat2d_rotate |
创建旋转矩阵 |
hom_mat2d_scale |
创建缩放矩阵 |
affine_trans_image |
应用矩阵变换 |
3. 手动实现图像平移
3.1 构建平移矩阵
让我们从最简单的平移开始,手动构建变换矩阵:
* 定义平移量
tx := 64
ty := 64
* 创建平移矩阵
create_matrix(3, 3, [1,0,tx, 0,1,ty, 0,0,1], TranslateMatrix)
3.2 应用变换的两种方法
方法一:正向映射(遍历原图)
* 遍历原图像素
for x := 0 to Height-1 by 1
for y := 0 to Width-1 by 1
* 获取原图像素值
get_grayval(Image, x, y, Grayval)
* 构建齐次坐标向量
create_matrix(3, 1, [x,y,1], CoordVector)
* 应用变换
mult_matrix(TranslateMatrix, CoordVector, 'AB', TransformedCoord)
* 获取变换后坐标
get_full_matrix(TransformedCoord, NewXY)
* 在新图像中设置像素值
if (NewXY[0] >= 0 and NewXY[0] < Height and
NewXY[1] >= 0 and NewXY[1] < Width)
set_grayval(ImageTranslated, NewXY[0], NewXY[1], Grayval)
endif
endfor
endfor
方法二:逆向映射(遍历目标图)
逆向映射可以避免出现空洞,是更推荐的方法:
* 创建目标图像
gen_image_const(ImageTranslated, 'byte', Width, Height)
* 获取平移矩阵的逆矩阵
invert_matrix(TranslateMatrix, 'general', 0, InverseTranslateMatrix)
* 遍历目标图像
for newX := 0 to Height-1 by 1
for newY := 0 to Width-1 by 1
* 构建目标坐标向量
create_matrix(3, 1, [newX,newY,1], TargetCoord)
* 计算对应的原图坐标
mult_matrix(InverseTranslateMatrix, TargetCoord, 'AB', SourceCoord)
get_full_matrix(SourceCoord, OrigXY)
* 边界检查
if (OrigXY[0] >= 0 and OrigXY[0] < Height and
OrigXY[1] >= 0 and OrigXY[1] < Width)
* 获取原图像素值
get_grayval(Image, OrigXY[0], OrigXY[1], Grayval)
set_grayval(ImageTranslated, newX, newY, Grayval)
endif
endfor
endfor
4. 实现图像旋转
4.1 旋转矩阵的构建
旋转矩阵需要考虑角度与弧度的转换:
* 定义旋转角度(45度)
angle_deg := 45
angle_rad := rad(angle_deg)
* 构建旋转矩阵
create_matrix(3, 3,
[cos(angle_rad), -sin(angle_rad), 0,
sin(angle_rad), cos(angle_rad), 0,
0, 0, 1],
RotateMatrix)
4.2 处理旋转中的插值问题
旋转会导致像素位置的非整数映射,需要使用插值:
* 双线性插值函数
procedure double_biline (Image, Value_x, Value_y, pout)
* 边界处理
get_image_size(Image, Width, Height)
if (Value_x < 0 or Value_y < 0 or
Value_x > Height-1 or Value_y > Width-1)
pout := -1
return ()
endif
* 获取相邻整数坐标
tuple_floor(Value_x, x1)
x1 := int(x1)
tuple_ceil(Value_x, x2)
x2 := int(x2)
tuple_floor(Value_y, y1)
y1 := int(y1)
tuple_ceil(Value_y, y2)
y2 := int(y2)
* 获取四个相邻点的像素值
get_grayval(Image, x1, y1, p1)
get_grayval(Image, x2, y1, p2)
get_grayval(Image, x1, y2, p3)
get_grayval(Image, x2, y2, p4)
* 执行双线性插值
if (x1 == x2)
px1 := p1
px2 := p3
else
px1 := p1 + (p2 - p1) * (Value_x - x1) / (x2 - x1)
px2 := p3 + (p4 - p3) * (Value_x - x1) / (x2 - x1)
endif
if (y1 == y2)
pout := px1
else
pout := px1 + (px2 - px1) * (Value_y - y1) / (y2 - y1)
endif
endprocedure
4.3 应用旋转矩阵
* 获取旋转矩阵的逆矩阵
invert_matrix(RotateMatrix, 'general', 0, InverseRotateMatrix)
* 创建目标图像
gen_image_const(ImageRotated, 'byte', Width, Height)
* 遍历目标图像
for x := 0 to Height-1 by 1
for y := 0 to Width-1 by 1
* 构建目标坐标
create_matrix(3, 1, [x,y,1], TargetCoord)
* 计算对应的原图坐标
mult_matrix(InverseRotateMatrix, TargetCoord, 'AB', SourceCoord)
get_full_matrix(SourceCoord, OrigXY)
* 使用双线性插值获取像素值
double_biline(Image, OrigXY[0], OrigXY[1], Grayval)
if (Grayval != -1)
set_grayval(ImageRotated, x, y, Grayval)
endif
endfor
endfor
5. 组合变换与性能优化
5.1 变换矩阵的组合
通过矩阵乘法,我们可以将多个变换组合成一个复合变换:
* 先旋转再平移
create_matrix(3, 3, [1,0,50, 0,1,50, 0,0,1], TranslateMatrix)
create_matrix(3, 3,
[cos(rad(30)), -sin(rad(30)), 0,
sin(rad(30)), cos(rad(30)), 0,
0, 0, 1],
RotateMatrix)
* 组合变换:T = 平移 × 旋转
mult_matrix(TranslateMatrix, RotateMatrix, 'AB', CombinedMatrix)
5.2 性能优化技巧
- 矩阵预计算:提前计算好所有变换矩阵,避免在循环中重复计算
- 批量操作:使用Halcon的向量化操作替代逐像素处理
- 内存管理:及时释放不再使用的矩阵句柄
* 优化后的旋转实现
procedure optimized_rotate (Image, angle_deg, ImageRotated)
* 预计算矩阵
angle_rad := rad(angle_deg)
create_matrix(3, 3,
[cos(angle_rad), -sin(angle_rad), 0,
sin(angle_rad), cos(angle_rad), 0,
0, 0, 1],
RotateMatrix)
invert_matrix(RotateMatrix, 'general', 0, InverseRotateMatrix)
* 获取图像尺寸
get_image_size(Image, Width, Height)
gen_image_const(ImageRotated, 'byte', Width, Height)
* 批量处理坐标
create_matrix(3, Height*Width, [...], AllCoords) // 实际代码需填充所有坐标
mult_matrix(InverseRotateMatrix, AllCoords, 'AB', TransformedCoords)
* 批量插值和赋值
// 实际实现会更复杂,这里展示思路
endprocedure
更多推荐


所有评论(0)