使用 ORB 检测器查找关键点¶
ORB 检测器用于视频稳定、全景创建、物体检测、三维重建、摄像机运动估计、图像对齐和增强现实的定位。它还可通过关键点数据库识别建筑物或地标等位置。
理论部分¶
ORB(Oriented FAST and Rotated BRIEF) 是一种快速关键点检测器和描述器。它结合了 FAST(用于关键点检测)和 BRIEF(用于关键点描述符)算法。
FAST(来自加速片段测试的特征)** 算法用于查找图像中的角。 Harris Corner Measure (哈里斯角测量)用于选择最重要的点,以减少弱关键点的数量。每个关键点的计算都有一个方向。 这使得 ORB 不受图像旋转的影响。
BRIEF(二元健壮独立基本特征)算法可创建二元描述符。为了比较图像之间的点,ORB 使用汉明度量对二进制描述符进行成对比较。
本例将讨论 ORB 检测器的经典用法,即在两幅图像中找出关键点并进行比较。 根据计算出的同源性,图像将被对齐和合并,从而产生一幅全景图,展示将两幅图像合并为一幅图像的过程。
连接处理图像所需的软件包¶
import Pkg;
Pkg.add("Images")
Pkg.add("ImageFeatures")
Pkg.add("ImageDraw")
Pkg.add("ImageProjectiveGeometry")
Pkg.add("LinearAlgebra")
Pkg.add("OffsetArrays")
Pkg.add("ImageTransformations")
Pkg.add("StaticArrays");
using Pkg, Images, ImageFeatures, ImageDraw
using ImageProjectiveGeometry
using LinearAlgebra, OffsetArrays
using ImageTransformations, StaticArrays
上传图像¶
指定图片路径,上传并显示图片:
path_to_img_1 = "$(@__DIR__)/1.jpg"
path_to_img_2 = "$(@__DIR__)/2.jpg"
Image_1 = load(path_to_img_1)
Image_2 = load(path_to_img_2)
ORB 应用程序¶
初始化判别器
orb_params = ORB(num_keypoints = 1000);
让我们定义一个使用判别器在图像中查找关键点的函数
function find_features(img::AbstractArray, orb_params)
desc, ret_features = create_descriptor(Gray.(img), orb_params)
end;
让我们定义一个在两幅图像中搜索共同关键点的函数。首先,计算每幅图像的关键点和描述符,然后使用给定的阈值匹配描述符。
function match_points(img1::AbstractArray, img2::AbstractArray, orb_params, threshold::Float64=0.1)
desc_1, ret_features_1 = find_features(img1, orb_params)
desc_2, ret_features_2 = find_features(img2, orb_params)
matches = match_keypoints(ret_features_1, ret_features_2, desc_1, desc_2, threshold);
end;
让我们找出匹配的关键点
matches = match_points(Image_1, Image_2, orb_params, 0.35);
让我们定义一个可视化关键点关系的函数。pad_display
draw_matches
绘制连接共同关键点的线条。
function pad_display(img1, img2)
img1h = length(axes(img1, 1))
img2h = length(axes(img2, 1))
mx = max(img1h, img2h);
hcat(vcat(img1, zeros(RGB{Float64},
max(0, mx - img1h), length(axes(img1, 2)))),
vcat(img2, zeros(RGB{Float64},
max(0, mx - img2h), length(axes(img2, 2)))))
end
function draw_matches(img1, img2, matches)
grid = pad_display(parent(img1), parent(img2));
offset = CartesianIndex(0, size(img1, 2));
for m in matches
draw!(grid, LineSegment(m[1], m[2] + offset))
end
grid
end;
让我们看看输出结果如何
draw_matches(Image_1, Image_2, matches)
绘制全景图¶
计算同构(几何变换)需要两个图像中相互对应的点的坐标。
这里,两幅图像的点坐标是从匹配关键点列表matches
中提取的。 x1
- 是第一幅图像中的坐标,x2
是第二幅图像中的坐标。
x1 = hcat([Float64[m[1].I[1], m[1].I[2]] for m in matches]...) # 2xN
x2 = hcat([Float64[m[2].I[1], m[2].I[2]] for m in matches]...); # 2xN
在这里,使用 RANSAC 方法找到同构矩阵H
,使两组点x1
和x2
尽可能紧密地对齐。
t = 0.01
# Вычисление гомографии с помощью RANSAC
H, inliers = ransacfithomography(x1, x2, t);
t
- 是一个阈值,用于确定在应用同轴度量法后,各点相差多少才算 "正确"(离群值)。
结构Homography
表示同构矩阵。它包含一个 3x3 矩阵,定义了两幅图像之间的变换。
struct Homography{T}
m::SMatrix{3, 3, T, 9}
end
Homography(m::AbstractMatrix{T}) where {T} = Homography{T}(SMatrix{3, 3, T, 9}(m))
function (trans::Homography{M})(x::SVector{3}) where M
out = trans.m * x
out = out / out[end]
SVector{2}(out[1:2])
end
function (trans::Homography{M})(x::SVector{2}) where M
trans(SVector{3}([x[1], x[2], 1.0]))
end
function (trans::Homography{M})(x::CartesianIndex{2}) where M
trans(SVector{3}([collect(x.I)..., 1]))
end
function (trans::Homography{M})(x::Tuple{Int, Int}) where M
trans(CartesianIndex(x))
end
function (trans::Homography{M})(x::Array{CartesianIndex{2}, 1}) where M
CartesianIndex{2}.([tuple(y...) for y in trunc.(Int, collect.(trans.(x)))])
end
function Base.inv(trans::Homography{M}) where M
i = inv(trans.m)
Homography(i ./ i[end])
end
使用函数warp
,将同构矩阵H
应用于图像Image_1
,创建转换后的图像new_img
。
new_img = warp(Image_1, Homography(H))
该函数将两幅图像--原始图像和变换后的图像--合并为一幅共同的画布,并在旧图像上添加新图像。
function merge_images(img1, new_img)
# Вычисляем размеры холста
axis1_size = max(last(axes(new_img, 1)), size(img1, 1)) - min(first(axes(new_img, 1)), 1) + 1
axis2_size = max(last(axes(new_img, 2)), size(img1, 2)) - min(first(axes(new_img, 2)), 1) + 1
# Создаем OffsetArray для объединённого изображения
combined_image = OffsetArray(
zeros(RGB{N0f8}, axis1_size, axis2_size), (
min(0, first(axes(new_img, 1))),
min(0, first(axes(new_img, 2)))))
# Копируем первое изображение в общий холст
combined_image[1:size(img1, 1), 1:size(img1, 2)] .= img1
# Копируем второе изображение в общий холст
for i in axes(new_img, 1)
for j in axes(new_img, 2)
if new_img[i, j] != colorant"black" # Пропускаем чёрные пиксели
combined_image[i, j] = new_img[i, j]
end
end
end
combined_image
end
panorama = merge_images(Image_1, new_img)
结论¶
本示例演示了如何使用 ORB 检测器自动查找关键点并将其与两幅图像进行匹配。构建的同构图像使图像得以对齐,将它们组合起来就能创建一个全景图。