碎纸片复原

模型建立

问题1

边缘相似度

问题一给出的是一单页页面仅纵切出的 19 条碎纸片,确定碎纸片排列的顺序,就能很好的还原出原来的完整纸片。因为碎纸片的形状规则且大小相等,因此不能够通过碎纸片边缘形状来确定相邻纸片,只能通过分析边缘文字特征进行拼接。可以看出,碎纸片之间的切口都是整齐的直线,碎纸片边缘保留了字符信息。通过比较两个纸片边缘相似度,可以确定两张纸片是否相邻,从而得到正确的拼接序列。

一般来讲,从图像的连通性考虑,相邻的两个碎纸片的边缘像素应当是相似、甚至是相同的。这样我们可以将两个边缘的匹配指标用两个向量的距离来衡量:


图1

其中,x和y表示两张碎纸图片的像素矩阵的边缘列向量。如果两个由像素组成的向量间的距离为0,则可以肯定两张碎纸片肯定相邻,但这是理想的情况,如图2所示,碎纸图片不是矢量图形,在显示点阵字体时,会出现锯齿现象,文字边缘由里向外,会有从黑到白之间的过渡,所以两个相邻像素向量间的距离一般较小,但不一定为0。虽然像素分开了,由于汉字字体或者英文字体大部分是连体的,所以这些碎片的图像灰度信息会有一定的相关性或者说是连续性。我们就能利用这些碎片之间的相关性还原出完整纸片。


图2

贪心算法

由于存在锯齿现象,两个向量间距离不一定为零,一个碎纸图片可能与多张其他碎纸片有相关性。所以,我们选择主要的步骤是找出一个起始碎片作为起点,然后把这个碎片像素矩阵的最右边缘向量跟其他碎片的最左边缘向量进行比较,选择匹配度最高的碎片进行匹配,然后以新匹配到的碎片为开始,再对余下碎片进行最优匹配,不断循环,直到所有碎纸片都匹配结束。如图3所示,由于选择的起始碎片对算法影响较大,为拼接出正确的纸片,我们需要找出原纸片中最左边的碎纸片编号。通过观察,我们看出文字与页面之间存在内边距,左侧留白最多的碎纸片就是原纸片中的最左边。通过比较留白大小找出起始碎片后,即可拼接出完整中文纸片。英文字符的碎纸片同样有相同的规律,使用相同的算法处理,就能得到英文的完整纸片。


图片3

问题求解

附件一和附件二

在处理附件一和附件二时,不需要进行人工干预,运行算法就能得到拼接顺序,最后利用python的PIL库完成碎片的 拼接。
最终附件一的拼接顺序为:

[8, 14, 12, 15, 3, 10, 2, 16, 1, 4, 5, 9, 13, 18, 11, 7, 17, 0, 6]

附件二的拼接顺序为:

[3, 6, 2, 7, 15, 18, 11, 0, 5, 1, 9, 13, 10, 8, 12, 14, 17, 16, 4]

图4为附件一拼接完成后的效果,图5为附件二拼接完成的效果


图片4
图片5

代码

附件一和二代码:

import glob
import numpy as np
from PIL import Image


class PaperRecovery:
    IMAGE_ABS_PATH = 'F:\code\py\paper-recovery\碎纸片1\*.bmp' #图片存在该目录下
    img = {}
    finded = set()

    def read_img(self):
        """
        读取指定目录下的碎纸图片,存入字典中,方便使用
        """
        img_name_list = glob.glob(self.IMAGE_ABS_PATH)
        for img_name in img_name_list:
            # k = img_name.replace('.bmp','')[-3:]
            # 使用文件路径作为字典的键,方便找出正确图片顺序后,拼接还原图片
            k = img_name
            self.img[k] = Image.open(img_name)

    def __init__(self):
        self.read_img()

    def find_match_paper(self,paper_img,direction):
        """
        根据图片边缘的相似度,找出给定碎纸片的相邻纸片
        """
        self_img_array = np.array(self.img[paper_img])
        sh, sw = self_img_array.shape
        if direction == "r":
            self_edge = self_img_array[0:sh,sw-1:sw]
        elif direction == 'l':
            self_edge = self_img_array[0:sh,0:1]
        min_var = -1
        for k, v in self.img.items():
            if k == paper_img:
                continue
            if k in self.finded:
                continue
            other_img_array = np.array(v)
            h, w = other_img_array.shape
            if direction == "r":
                other_edge = other_img_array[0:h,0:1]
            elif direction == 'l':
                other_edge = other_img_array[0:h,w-1:w]
            else:
                pass
            var = np.sum(abs(self_edge-other_edge))
            if min_var == -1:
                similar_img = k
                min_var = var
            if var < min_var:
                 similar_img = k
                 min_var = var
        self.finded.add(paper_img)
        return similar_img

    def find_edge_paper(self):
        """
        函数找出原图片中的最左边和最右边的碎纸图片
        观察碎纸图片后,可以看出,在竖切时
        在完整纸片的最左端和最右端的碎纸片,有一定的留白
        """
        def is_all_white(edge_array):
            """
            判断一列像素值是否全为255,即全白
            """
            WHITE_RGB = 255
            for k in edge_array:
                if k != WHITE_RGB:
                    return False
            return True

        for k, v in self.img.items():
            img_array = np.array(v)
            h, w = img_array.shape
            right_edge = img_array[0:h,w-1:w]
            left_edge = img_array[0:h,0:1]
            if is_all_white(right_edge):
                right_img_name = k
            elif is_all_white(left_edge):
                left_img_name = k
        return (left_img_name,right_img_name)


    def find_correct_order(self):
        correct_order = []
        left_side_img, right_side_img = self.find_edge_paper()
        correct_order.append(left_side_img)
        paper_list = list(self.img.keys())
        paper_list.remove(left_side_img)
        paper_list.remove(right_side_img)
        while paper_list:
            now_paper = correct_order[len(correct_order)-1]
            next_paper = self.find_match_paper(now_paper,direction="r")
            paper_list.remove(next_paper)
            correct_order.append(next_paper)
        correct_order.append(right_side_img)
        return correct_order

    def combining(self,order):
        """
        复原竖切的碎纸片
        按照正确的图片顺序(从左到右),将碎纸片拼接成完整的纸片
        """
        UNIT_W, UNIT_H = self.img[order[0]].size
        TARGET_WIDTH = len(order) * UNIT_W
        target = Image.new('RGB', (TARGET_WIDTH, UNIT_H))
        x = 0
        for img_name in order:
            img = self.img[img_name]
            target.paste(img,(x,0))
            x += UNIT_W
        return target
        


if __name__ == "__main__":
    rp = PaperRecovery()
    correct_order = rp.find_correct_order()
    whole_img = rp.combining(correct_order)
    whole_img.save('whole.bmp')
    idx_list = []
    for order in correct_order:
        idx = order[-7:-3]
        idx_list.append(idx)
    print(idx_list)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 在和孩子争吵后,我愤怒的冲出屋外,在浓浓的雾霾中踱起步来。虽然屋外昏昏暗暗但还很亮,有爱护身体的都捂着口罩急...
    风若儿阅读 310评论 1 2
  • 最近跟宋一一互动的太少了,自己在玩手机,他在看电视,天气不好,心情也不好!感觉不能再这样下去了,但是还是没有什么改...
    一一麻麻love一一阅读 99评论 0 0
  • 在潇潇的雨地里 我邂逅了你 纯洁美丽的广玉兰 粉白殷红的大朵花瓣 在雨里灼灼地盛开 像少女娇羞白皙的脸庞 繁密热闹...
    端阳香草阅读 336评论 2 7