一、系统架构
图像预处理 → 边缘检测 → 特征匹配 → 拼接优化 → 完整重建
二、MATLAB 代码
2.1 主程序 paper_puzzle_solver.m
matlab
%% 碎纸片自动拼接系统
clear; clc; close all;
%% ========== 1. 读取碎纸片 ==========
% 假设碎片存放在 'fragments/' 文件夹中
fragment_dir = 'fragments/';
file_list = dir(fullfile(fragment_dir, '*.jpg'));
if isempty(file_list)
% 如果没有真实碎片,生成模拟碎片用于演示
fragments = generate_synthetic_fragments(8, [200, 150]);
N = length(fragments);
fprintf('生成 %d 个模拟碎片\n', N);
else
N = length(file_list);
fragments = cell(N,1);
for i = 1:N
img_path = fullfile(fragment_dir, file_list(i).name);
fragments{i} = imread(img_path);
if size(fragments{i},3) == 3
fragments{i} = rgb2gray(fragments{i});
end
end
fprintf('读取 %d 个真实碎片\n', N);
end
%% ========== 2. 预处理与特征提取 ==========
fprintf('正在提取碎片特征...\n');
features = cell(N,1);
edges = cell(N,1);
for i = 1:N
% 预处理
frag = fragments{i};
frag = im2double(frag);
% 二值化(假设文字为黑色)
bw = imbinarize(frag, 'adaptive');
bw = ~bw; % 反转:文字为白色背景为黑
% 边缘检测
edge_map = edge(bw, 'canny', [0.1, 0.3]);
edges{i} = edge_map;
% 提取边缘特征(四个边的像素序列)
features{i} = extract_edge_features(edge_map);
end
%% ========== 3. 碎片匹配与拼接 ==========
fprintf('正在进行碎片匹配...\n');
% 构建相似度矩阵
similarity_matrix = zeros(N, N, 4); % [i,j,方向] 方向: 1=右接左, 2=左接右, 3=下接上, 4=上接下
for i = 1:N
for j = 1:N
if i ~= j
% 计算四个方向的匹配度
similarity_matrix(i,j,1) = match_edges(features{i}.right, features{j}.left); % i右接j左
similarity_matrix(i,j,2) = match_edges(features{i}.left, features{j}.right); % i左接j右
similarity_matrix(i,j,3) = match_edges(features{i}.bottom, features{j}.top); % i下接j上
similarity_matrix(i,j,4) = match_edges(features{i}.top, features{j}.bottom); % i上接j下
end
end
end
%% ========== 4. 构建拼接图 ==========
fprintf('构建拼接序列...\n');
[assembly_order, assembly_positions] = build_assembly_sequence(similarity_matrix);
%% ========== 5. 图像重建 ==========
fprintf('重建完整图像...\n');
reconstructed_img = reconstruct_image(fragments, assembly_order, assembly_positions);
%% ========== 6. 结果显示 ==========
figure('Position', [100, 100, 1400, 600]);
% 显示所有碎片
subplot(2,4,1); montage(fragments, 'Size', [ceil(N/4), 4]);
title('所有碎纸片'); axis image off;
% 显示拼接序列
subplot(2,4,2);
plot_assembly_order(assembly_order, assembly_positions);
title('拼接序列与位置');
% 显示重建结果
subplot(2,4,3); imshow(reconstructed_img);
title('重建的完整图像');
% 显示匹配质量
subplot(2,4,4);
plot_matching_quality(similarity_matrix, assembly_order);
title('匹配质量评估');
sgtitle('碎纸片自动拼接系统', 'FontSize', 14, 'FontWeight', 'bold');
%% ========== 7. 保存结果 ==========
imwrite(reconstructed_img, 'reconstructed_paper.jpg');
fprintf('重建图像已保存为 reconstructed_paper.jpg\n');
2.2 边缘特征提取函数 extract_edge_features.m
matlab
function features = extract_edge_features(edge_map)
% 提取四个边的边缘特征
[h, w] = size(edge_map);
% 提取四条边(宽度10像素)
border_width = 10;
% 左边
left_edge = edge_map(:, 1:border_width);
features.left = mean(left_edge, 2); % 垂直方向平均
% 右边
right_edge = edge_map(:, w-border_width+1:w);
features.right = mean(right_edge, 2);
% 上边
top_edge = edge_map(1:border_width, :);
features.top = mean(top_edge, 1)'; % 水平方向平均
% 下边
bottom_edge = edge_map(h-border_width+1:h, :);
features.bottom = mean(bottom_edge, 1)';
% 计算边缘密度
features.left_density = sum(left_edge(:)) / numel(left_edge);
features.right_density = sum(right_edge(:)) / numel(right_edge);
features.top_density = sum(top_edge(:)) / numel(top_edge);
features.bottom_density = sum(bottom_edge(:)) / numel(bottom_edge);
end
2.3 边缘匹配函数 match_edges.m
matlab
function score = match_edges(edge1, edge2)
% 计算两个边缘的匹配度(0-1之间,越高越好)
if isempty(edge1) || isempty(edge2)
score = 0;
return;
end
% 确保长度一致
len = min(length(edge1), length(edge2));
edge1 = edge1(1:len);
edge2 = edge2(1:len);
% 方法1:相关系数
corr_coef = corr(edge1, edge2);
if isnan(corr_coef)
corr_coef = 0;
end
% 方法2:欧氏距离(归一化为相似度)
dist = norm(edge1 - edge2);
max_dist = sqrt(len); % 最大可能距离
dist_score = 1 - dist/(max_dist + eps);
% 方法3:边缘重叠度
overlap = sum(edge1 .* edge2) / (sum(edge1) + sum(edge2) + eps);
% 综合评分
score = 0.4*corr_coef + 0.3*dist_score + 0.3*overlap;
score = max(0, min(1, score)); % 限制在0-1之间
end
2.4 拼接序列构建函数 build_assembly_sequence.m
matlab
function [order, positions] = build_assembly_sequence(sim_mat)
[N, ~, ~] = size(sim_mat);
% 找到最佳匹配对
best_score = -inf;
best_pair = [];
best_dir = 0;
for i = 1:N
for j = 1:N
if i ~= j
for d = 1:4
if sim_mat(i,j,d) > best_score
best_score = sim_mat(i,j,d);
best_pair = [i, j];
best_dir = d;
end
end
end
end
end
% 构建拼接序列
order = best_pair;
positions = zeros(N, 2); % [x, y] 位置
% 根据方向设置初始位置
if best_dir == 1 % i右接j左
positions(order(1), :) = [0, 0];
positions(order(2), :) = [100, 0]; % 水平偏移
elseif best_dir == 2 % i左接j右
positions(order(1), :) = [100, 0];
positions(order(2), :) = [0, 0];
elseif best_dir == 3 % i下接j上
positions(order(1), :) = [0, 0];
positions(order(2), :) = [0, 100]; % 垂直偏移
elseif best_dir == 4 % i上接j下
positions(order(1), :) = [0, 100];
positions(order(2), :) = [0, 0];
end
% 逐步添加剩余碎片
used = false(N,1);
used(order) = true;
while sum(used) < N
best_add_score = -inf;
best_add_idx = -1;
best_base_idx = -1;
best_add_dir = 0;
for base_idx = 1:N
if used(base_idx)
for add_idx = 1:N
if ~used(add_idx)
for d = 1:4
if sim_mat(base_idx, add_idx, d) > best_add_score
best_add_score = sim_mat(base_idx, add_idx, d);
best_add_idx = add_idx;
best_base_idx = base_idx;
best_add_dir = d;
end
end
end
end
end
end
% 添加最佳碎片
order = [order, best_add_idx];
used(best_add_idx) = true;
% 更新位置
if best_add_dir == 1 % 基右接新增左
positions(best_add_idx, :) = positions(best_base_idx, :) + [100, 0];
elseif best_add_dir == 2 % 基左接新增右
positions(best_add_idx, :) = positions(best_base_idx, :) + [-100, 0];
elseif best_add_dir == 3 % 基下接新增上
positions(best_add_idx, :) = positions(best_base_idx, :) + [0, 100];
elseif best_add_dir == 4 % 基上接新增下
positions(best_add_idx, :) = positions(best_base_idx, :) + [0, -100];
end
end
end
2.5 图像重建函数 reconstruct_image.m
matlab
function reconstructed = reconstruct_image(fragments, order, positions)
% 根据拼接序列重建完整图像
N = length(fragments);
% 计算画布大小
pos_x = positions(:,1);
pos_y = positions(:,2);
canvas_width = max(pos_x) - min(pos_x) + size(fragments{1},2);
canvas_height = max(pos_y) - min(pos_y) + size(fragments{1},1);
% 创建画布
reconstructed = ones(canvas_height, canvas_width, 3); % 白色背景
% 放置每个碎片
for i = 1:N
frag = fragments{order(i)};
if size(frag,3) == 1
frag = repmat(frag, [1,1,3]); % 灰度转RGB
end
% 计算放置位置(考虑负坐标)
x_offset = pos_x(i) - min(pos_x) + 1;
y_offset = pos_y(i) - min(pos_y) + 1;
% 放置碎片
[h,w,~] = size(frag);
reconstructed(y_offset:y_offset+h-1, x_offset:x_offset+w-1, :) = frag;
end
% 裁剪空白边缘
reconstructed = crop_white_borders(reconstructed);
end
2.6 辅助函数(模拟碎片生成)
matlab
function fragments = generate_synthetic_fragments(num_fragments, fragment_size)
% 生成模拟碎纸片(用于演示)
fragments = cell(num_fragments,1);
% 创建包含文字的模拟文档
doc_img = create_document_image();
% 随机切割
[h,w,~] = size(doc_img);
for i = 1:num_fragments
% 随机位置和大小
x = randi([1, w-fragment_size(2)]);
y = randi([1, h-fragment_size(1)]);
fragment = doc_img(y:y+fragment_size(1)-1, x:x+fragment_size(2)-1, :);
fragments{i} = fragment;
end
end
function doc_img = create_document_image()
% 创建包含文字的文档图像
doc_img = ones(800, 600, 3); % 白色背景
% 添加黑色文字
text_lines = {
'碎纸片自动拼接系统',
'基于边缘特征匹配算法',
'2013年全国大学生数学建模竞赛',
'计算机视觉与图像处理',
'边缘检测与特征提取',
'相似度计算与图构建',
'最优拼接序列搜索',
'完整图像重建'
};
for i = 1:length(text_lines)
text_pos = [50, 100 + (i-1)*80];
doc_img = insertText(doc_img, text_pos, text_lines{i}, ...
'FontSize', 24, 'TextColor', 'black', 'BoxOpacity', 0);
end
end
function cropped = crop_white_borders(img)
% 裁剪白色边框
gray = rgb2gray(img);
bw = gray < 250; % 非白色区域
% 找到边界
rows = any(bw, 2);
cols = any(bw, 1);
row_start = find(rows, 1, 'first');
row_end = find(rows, 1, 'last');
col_start = find(cols, 1, 'first');
col_end = find(cols, 1, 'last');
cropped = img(row_start:row_end, col_start:col_end, :);
end
三、运行说明
3.1 准备碎纸片
- 真实碎片 :将碎纸片扫描为JPG/PNG格式,放入
fragments/文件夹 - 模拟碎片:直接运行代码,会自动生成模拟碎片
3.2 参数调整
border_width:边缘特征提取宽度(建议5-20像素)sim_mat权重:调整匹配评分公式中的权重系数- 拼接方向:根据实际碎片形状调整允许的拼接方向
3.3 预期结果
- 程序会输出拼接序列和重建的完整图像
- 显示匹配质量和拼接位置
- 保存重建图像为
reconstructed_paper.jpg
四、算法优化建议
4.1 提高匹配精度
matlab
% 使用更鲁棒的边缘描述子
features.hog = extractHOGFeatures(edge_map); % HOG特征
features.lbp = extractLBPFeatures(edge_map); % LBP特征
4.2 处理旋转碎片
matlab
% 尝试多个旋转角度
angles = [0, 90, 180, 270];
for angle = angles
rotated_frag = imrotate(frag, angle);
% 进行匹配...
end
4.3 图论优化
matlab
% 使用图论寻找最优拼接路径
G = graph(similarity_matrix(:,:,1)); % 构建图
[path, cost] = shortestpath(G, start_node, end_node);
参考代码 Matlab碎纸片拼接 www.youwenfan.com/contentcsw/81782.html
五、数学建模竞赛要点
| 要点 | 说明 |
|---|---|
| 特征提取 | 边缘密度、边缘连续性、文字行对齐 |
| 匹配度量 | 相关系数、欧氏距离、重叠度 |
| 拼接约束 | 碎片不能重叠、边界连续 |
| 优化目标 | 最大化整体匹配度、最小化边界不连续 |
六、常见问题解决
- 拼接错位:调整边缘特征提取宽度,使用更严格的匹配阈值
- 碎片丢失:检查相似度矩阵,确保所有碎片都有合适匹配
- 图像扭曲:考虑透视变换,使用特征点匹配(SIFT/SURF)