@
賽題解析
題目
2013建模國賽年B題第一問 碎紙片的拼接復原
破碎文件的拼接在司法物證復原、歷史文獻修復以及軍事情報獲取等領域都有着重要的應用。傳統上,拼接復原工作需由人工完成,准確率較高,但效率很低。特別是當碎片數量巨大,人工拼接很難在短時間內完成任務。隨着計算機技術的發展,人們試圖開發碎紙片的自動拼接技術,以提高拼接復原效率。縱切片如下(共19張):


接下來討論這個問題:對於給定的來自同一頁印刷文字文件的碎紙機破碎紙片(僅縱切),建立碎紙片拼接復原模型和算法。
我們在全國大學生數學建模競賽上可以下載到這道題目所給的圖片數據。
全國大學生數學建模競賽官網: 歷年賽題.
如果對數學建模歷年所有題目感興趣也歡迎下載我整理好的資料:全套
解題思路
我們首先會得到一張完整詩歌圖片的19張等長縱切片,這些圖片被完全打亂了順序。我們所要做的就是創建一個合理的模型來實現對所有碎片的重排序與拼接。
首先我們知道,我們得到的碎片如果不是在左右兩邊,那么它的左右兩邊都是有可能有不完整的漢字的。如果我們把這些圖片轉換成0-1像素矩陣(0表示黑色,1表示白色),那么任意兩個處於中間位置的圖片,位於左方圖片的最右邊與右方圖片的最左邊,每一行對應的值基本是相等的。此時我們用列向量相減的方法,得到另一個列向量,它表示任一碎片的最左邊與另一張碎片的最右邊像素列向量每一行對應的差值,再求和以此來表示兩張碎片之間的"距離"。之后我們再對這些"距離"進行排序,找到最小的那個,就表示這個"距離"對應的兩張碎片是相臨的。
算法細節
- 用imread函數讀取圖片並轉換成0-1矩陣(0表示黑色,1表示白色)。
- 首先計算每張圖片的第一列與最后一列的總和,找出第一張圖片(最左邊)和最后一張圖片(最右邊)。
- 從左邊的開始,以此計算它與剩下的每個碎片的最右邊的"距離",再找出最小的那個,就代表它們相鄰。
- 我在這設置了一個類似於C語言指針的變量p,這里p始終指向當前處理的碎片,即要找出與它右相鄰的另一張碎片。(p表示一組行向量的下標,具體見代碼。)
- 繼續的進行第4步,直到p指向之前已經找到的最右邊的碎片。
- 將對應的矩陣按順序拼接起來,然后用imshow函數輸出顯示。
這套算法我是用matlab實現的,但是由於本人對matlab的理解過於淺薄,對矩陣運算理解的還不夠,所以希望各位大神多多指出我的不足。
運行結果

Matlab源碼
此處展示以上解析的源碼,如何運用最小距離方法將分成19列的碎紙片拼接成一張完整的圖片。
clc
clear
close all
%1、把碎片的矩陣進行提取
%2、把矩陣轉換為向量(行和或者行平均)
%3、對11*19個向量運用聚類(系統聚類:向量之間的距離用相關系數、類與類之間的距離用ward)
%4、對每一類用第一題中的算法進行分類
pic1=zeros(1980,72,19);
pic3=zeros(1980,1368);
for i=0:18
s=strcat(int2str(i),'.bmp');
pic1(:,:,i+1)=imread(s);
end
%%%將圖片二值化
for i=1:19
for j=1:1980
for p=1:72
if pic1(j,p,i)~=255
pic1(j,p,i)=1;
else
pic1(j,p,i)=0;%黑色為0,白色為1
end
end
end
end
r=zeros(19);
for i=1:19
for j=i:19
r(i,j)=sum(abs(pic1(:,1,i)-pic1(:,end,j)));
end
end
for i=1:19
for j=1:i
r(i,j)=sum(abs(pic1(:,end,i)-pic1(:,1,j)));
end
end
for i=1:19
r(i,i)=inf;
end
for i=1:19
if pic1(:,1,i)==0
first_pic=i;%找到第一張圖片
end
if pic1(:,end,i)==0
end_pic=i;%找到最后一張圖片
end
end
r1=1980*ones(1,19);
rank_pic=zeros(1,19);
p1=first_pic;
xuhao=1;
rank_pic(xuhao)=first_pic;
cjl=0;%當這個值為0時說明沒有重復,從第一個排序向量開始一開始p1=first,之后我們都要判定當前計算的i值是否已經出現過,如果出現過那么就跳過不計算。
while p1~=end_pic
for i=1:19
for j=1:i
if i==rank_pic(j)
cjl=1;
end
end
if i~=p1 && cjl==0
r1(i)=sum(sum(abs(pic1(:,end,p1)-pic1(:,1,i))));
end
cjl=0;
end
[~,label]=min(r1);
p1=label;
cjl=0;
r1=1980*ones(1,19);%將R1重新初始化!!!!
xuhao=xuhao+1;%序號遞增
rank_pic(xuhao)=label;%將當前得到的最短距離放入排好的序列
end
pic2=pic1(:,:,rank_pic(1));
for i=1:18
pic2=[pic2 pic1(:,:,rank_pic(i+1))];
end
[m,n]=size(pic2);
pic2=1-pic2;
imshow(pic2);
