ORB(Oriented FAST and Rotated BRIEF)是计算机视觉中一种高效的特征检测与描述算法,结合了FAST角点检测器和BRIEF描述符的优点。这个算法由Ethan Rublee等人在2011年提出,主要针对实时性要求高的应用场景。
ORB算法主要包含三个关键部分:
在MATLAB实现中,我们首先需要读取并预处理输入图像:
matlab复制img_1 = 'E:\MyCode\Matlab_prj\ORB_test\data\01_small.jpg';
img_2 = 'E:\MyCode\Matlab_prj\ORB_test\data\02_small.jpg';
% 读取两张灰度图像
img1 = imread(img_1);
img2 = imread(img_2);
% 转换为灰度图(如果需要)
if size(img1, 3) == 3
img1 = rgb2gray(img1);
end
if size(img2, 3) == 3
img2 = rgb2gray(img2);
end
FAST(Features from Accelerated Segment Test)算法通过比较像素点与其周围圆形邻域内像素的亮度差异来检测角点。在ORB中,我们使用FAST-16变体,即检查16个等距采样点:
matlab复制function points = fast_corner_detection(img, threshold)
[rows, cols] = size(img);
points = [];
points16 = [-3, 0; -3, 1; -2, 2; -1, 3;
0, 3; 1, 3; 2, 2; 3, 1;
3, 0; 3, -1; 2, -2; 1, -3;
0, -3; -1, -3; -2, -2; -3, -1];
% 遍历图像 (排除边界)
for r = 4:rows-4
for c = 4:cols-4
center = img(r, c);
is_corner = false;
% 检查16个点中是否有连续12个点满足条件
for start = 1:16
count_high = 0; % 大于中心+阈值
count_low = 0; % 小于中心-阈值
% 检查从start开始的连续12个点
for j = 1:12
idx = mod(start + j - 2, 16) + 1; % 环形索引
dy = points16(idx, 1);
dx = points16(idx, 2);
p = img(r + dy, c + dx);
if p > center + threshold
count_high = count_high + 1;
end
if p < center - threshold
count_low = count_low + 1;
end
end
% 满足条件则标记为角点
if count_high == 12 || count_low == 12
is_corner = true;
break;
end
end
if is_corner
points = [points; r, c]; % (y,c) = (行, 列)
end
end
end
% 非极大值抑制
nms_radius = 5;
[points, ~] = nms_and_harris(img, points, 1000, nms_radius, 0.04);
end
提示:FAST阈值的选择直接影响检测结果。阈值越大,检测到的角点越少但更稳定;阈值越小,检测到的角点越多但可能包含更多噪声。通常建议在10-30之间取值。
ORB通过计算特征点邻域内的图像矩来确定主方向,实现旋转不变性:
matlab复制function orientations = computeOrientation(img, keypoints, patch_size)
[rows, cols] = size(img);
num_keypoints = size(keypoints, 1);
orientations = zeros(num_keypoints, 1);
radius = floor(patch_size / 2);
for k = 1:num_keypoints
cy = keypoints(k, 1); % 特征点y坐标
cx = keypoints(k, 2); % 特征点x坐标
% 提取特征点周围的图像块
patch = img(cy-radius:cy+radius, cx-radius:cx+radius);
% 计算图像块的矩
[X, Y] = meshgrid(-radius:radius, -radius:radius);
m00 = sum(patch(:));
m10 = sum(X(:) .* double(patch(:)));
m01 = sum(Y(:) .* double(patch(:)));
% 计算质心坐标
centroid_x = m10 / m00;
centroid_y = m01 / m00;
% 计算从特征点到质心的向量角度
angle = atan2(centroid_y, centroid_x);
orientations(k) = mod(angle, 2*pi); % 归一化到[0, 2π)
end
end
BRIEF(Binary Robust Independent Elementary Features)描述符通过比较随机点对的像素强度生成二进制串。ORB改进为Rotated BRIEF,使其具有旋转不变性:
matlab复制function descriptors = computeRotatedBRIEF(img, keypoints, orientations, patch_size, num_pairs)
[rows, cols] = size(img);
num_keypoints = size(keypoints, 1);
descriptors = zeros(num_keypoints, num_pairs, 'uint8');
half_patch = floor(patch_size / 2);
% 生成随机点对(服从高斯分布)
rng(42); % 固定随机种子保证可重复性
sigma = patch_size / 5;
points1 = round(randn(num_pairs, 2) * sigma);
points2 = round(randn(num_pairs, 2) * sigma);
points1 = max(min(points1, half_patch), -half_patch);
points2 = max(min(points2, half_patch), -half_patch);
for k = 1:num_keypoints
cy = keypoints(k, 1);
cx = keypoints(k, 2);
angle = orientations(k);
% 创建旋转矩阵
cos_theta = cos(angle);
sin_theta = sin(angle);
for p = 1:num_pairs
% 获取原始坐标并旋转
y1 = points1(p, 1); x1 = points1(p, 2);
y2 = points2(p, 1); x2 = points2(p, 2);
x1_rot = x1 * cos_theta - y1 * sin_theta;
y1_rot = x1 * sin_theta + y1 * cos_theta;
x2_rot = x2 * cos_theta - y2 * sin_theta;
y2_rot = x2 * sin_theta + y2 * cos_theta;
% 转换到图像坐标并比较像素强度
img_x1 = round(cx + x1_rot); img_y1 = round(cy + y1_rot);
img_x2 = round(cx + x2_rot); img_y2 = round(cy + y2_rot);
if all([img_x1, img_y1, img_x2, img_y2] >= 1) && ...
img_x1 <= cols && img_y1 <= rows && ...
img_x2 <= cols && img_y2 <= rows
descriptors(k, p) = img(img_y1, img_x1) > img(img_y2, img_x2);
end
end
end
end
注意:描述符长度num_pairs通常取256,这会在速度和区分度之间取得良好平衡。更长的描述符提供更好的区分度但会增加计算量和存储需求。
ORB使用汉明距离(Hamming Distance)来比较二进制描述符的相似度:
matlab复制function [matches, distances] = matchDescriptorsBruteForce(desc1, desc2, max_distance, ratio_threshold)
[M, num_bits] = size(desc1);
[N, ~] = size(desc2);
matches = [];
distances = [];
for i = 1:M
% 计算当前描述符与所有目标描述符的距离
query_desc = desc1(i, :);
all_distances = sum(bitxor(query_desc, desc2), 2);
% 找到最小的两个距离
[sorted_dist, sorted_idx] = sort(all_distances);
if length(sorted_dist) >= 2
best_dist = sorted_dist(1);
second_best_dist = sorted_dist(2);
best_idx = sorted_idx(1);
% 应用比率测试和距离阈值
if best_dist <= max_distance && (best_dist / second_best_dist) < ratio_threshold
matches = [matches; i, best_idx];
distances = [distances; best_dist];
end
end
end
end
随机抽样一致(RANSAC)算法用于从匹配点对中估计鲁棒的单应性矩阵:
matlab复制function H = ransac_homography(points1, points2, matches, varargin)
% 参数设置
params.maxIterations = 500;
params.threshold = 3.0;
params.confidence = 0.99;
params.minInliers = 10;
% 提取匹配点坐标
num_matches = size(matches, 1);
matched_points1 = zeros(num_matches, 2);
matched_points2 = zeros(num_matches, 2);
for i = 1:num_matches
idx1 = matches(i, 1);
idx2 = matches(i, 2);
matched_points1(i, :) = points1(idx1, [2 1]); % 转换为[x,y]
matched_points2(i, :) = points2(idx2, [2 1]);
end
% RANSAC主循环
best_inliers = 0;
best_H = eye(3);
N = params.maxIterations;
for iter = 1:N
% 随机选择4个点对
indices = randperm(num_matches, 4);
% 计算单应性矩阵
try
H = computeHomographyDLT(matched_points1(indices, :), ...
matched_points2(indices, :));
catch
continue;
end
% 计算重投影误差
errors = computeReprojectionErrors(matched_points1, matched_points2, H);
% 统计内点
inlier_mask = errors < params.threshold;
inlier_count = sum(inlier_mask);
% 更新最佳模型
if inlier_count > best_inliers
best_inliers = inlier_count;
best_H = H;
best_inlier_indices = find(inlier_mask);
% 自适应调整迭代次数
inlier_ratio = inlier_count / num_matches;
N = min(params.maxIterations, ...
ceil(log(1-params.confidence)/log(1-inlier_ratio^4)));
end
end
% 用所有内点重新估计H
if best_inliers >= 4
H = computeHomographyDLT(matched_points1(best_inlier_indices, :), ...
matched_points2(best_inlier_indices, :));
else
H = best_H;
end
end
最后,我们使用估计的单应性矩阵对图像进行对齐:
matlab复制function aligned_img = warp_image(img, H, output_size)
rows = output_size(1);
cols = output_size(2);
aligned_img = zeros(rows, cols, 'uint8');
H_inv = inv(H);
for r = 1:rows
for c = 1:cols
% 计算输入图像坐标
p = [c, r, 1]';
p_in = H_inv * p;
p_in = p_in / p_in(3);
x = p_in(1); y = p_in(2);
% 双线性插值
if x >= 1 && x <= size(img,2) && y >= 1 && y <= size(img,1)
x1 = floor(x); x2 = ceil(x);
y1 = floor(y); y2 = ceil(y);
% 边界处理
if x1 == x2, x2 = x1 + 1; end
if y1 == y2, y2 = y1 + 1; end
x1 = min(max(x1, 1), size(img,2));
x2 = min(max(x2, 1), size(img,2));
y1 = min(max(y1, 1), size(img,1));
y2 = min(max(y2, 1), size(img,1));
% 插值计算
v11 = img(y1, x1); v12 = img(y1, x2);
v21 = img(y2, x1); v22 = img(y2, x2);
dx = x - x1; dy = y - y1;
val = (1-dx)*(1-dy)*v11 + dx*(1-dy)*v12 + ...
(1-dx)*dy*v21 + dx*dy*v22;
aligned_img(r, c) = round(val);
end
end
end
end
FAST阈值选择:
非极大值抑制半径:
RANSAC参数:
matlab复制function points = fast_corner_detection_pyramid(img, threshold, num_levels, scale_factor)
points_all = [];
current_img = img;
for level = 1:num_levels
% 在当前层级检测特征点
points = fast_corner_detection(current_img, threshold);
% 将坐标映射回原始图像尺寸
points(:,1) = points(:,1) * (scale_factor^(level-1));
points(:,2) = points(:,2) * (scale_factor^(level-1));
points_all = [points_all; points];
% 下采样图像
current_img = imresize(current_img, 1/scale_factor);
end
% 对全图特征点进行非极大值抑制
[points_all, ~] = nms_and_harris(img, points_all, 1000, 5, 0.04);
points = points_all;
end
matlab复制% 在特征点方向计算中使用并行
parfor k = 1:num_keypoints
% 方向计算代码...
end
matlab复制% 不好的做法:动态扩展数组
points = [];
for i = 1:N
points = [points; new_point];
end
% 好的做法:预分配
points = zeros(N, 2);
for i = 1:N
points(i,:) = new_point;
end
匹配效果差:
单应性矩阵估计失败:
对齐图像出现畸变:
在实际项目中,ORB算法因其速度和效果的良好平衡而被广泛应用。通过合理调整参数和优化实现,可以在保持实时性的同时获得稳定的特征匹配效果。