碎纸片自动拼接系统(MATLAB 实现)

一、系统架构

复制代码
图像预处理 → 边缘检测 → 特征匹配 → 拼接优化 → 完整重建

二、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 准备碎纸片

  1. 真实碎片 :将碎纸片扫描为JPG/PNG格式,放入 fragments/ 文件夹
  2. 模拟碎片:直接运行代码,会自动生成模拟碎片

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

五、数学建模竞赛要点

要点 说明
特征提取 边缘密度、边缘连续性、文字行对齐
匹配度量 相关系数、欧氏距离、重叠度
拼接约束 碎片不能重叠、边界连续
优化目标 最大化整体匹配度、最小化边界不连续

六、常见问题解决

  1. 拼接错位:调整边缘特征提取宽度,使用更严格的匹配阈值
  2. 碎片丢失:检查相似度矩阵,确保所有碎片都有合适匹配
  3. 图像扭曲:考虑透视变换,使用特征点匹配(SIFT/SURF)