阅读 150

OpenCV实现乱序碎片复原

这篇文章主要介绍了通过OpenCV 直方图相似度对比,实现将4张打乱顺序的碎片拼接复原并展示原图。文中的示例代码讲解详细,需要的朋友可以学习一下

目录
  • 题目

  • 算法思路

  • 源码展示

  • 结果演示

题目

将4张打乱顺序的碎片拼接复原并展示原图

算法思路

将x张碎片的左右边缘提取保存

左右边缘两两对比,将相似度超过预设阈值的碎片执行拼接操作,得到左右拼接好的碎片

提取左右拼接好的碎片的上下边缘

上下边缘两两对比,将相似度超过预设阈值的碎片执行拼接操作,得到原图

源码展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#include <opencv2/opencv.hpp>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>
#include <cstdlib>
#include <utility>
#include <opencv2/imgproc/types_c.h>
 
using namespace std;
using namespace cv;
 
/*
 * 问题: 将x张打乱顺序的碎片复原,将复原好的图片展示出来
 * 思路: 1. 将x张碎片的左右边缘提取保存
 *       2. 左右边缘两两对比,将相似度超过预设阈值的碎片执行拼接操作,得到左右拼接好的碎片
 *       3. 提取左右拼接好的碎片的上下边缘
 *       4. 上下边缘两两对比,将相似度超过预设阈值的碎片执行拼接操作,得到原图
*/
 
int n = 0;  //左右拼接时需要的迭代器
int m = 0;  //上下拼接时需要的迭代器
 
//读取碎片
vector<Mat> fragments_Imread(string files_name);
vector<Mat> fragments_LR_Imread(string files_name);     //读取左右拼接好的碎片
 
//保存每张碎片的左右边缘
vector <vector<Mat>> edge_resection_LR(const vector <Mat>& fragments);
 
//直方图对比
bool compare_by_hist(const Mat& img1, const Mat& img2);
 
//左右拼接
void picture_stitching_LR(const Mat& img1, const Mat& img2);
 
//对每张碎片的左右边缘相互对比拼接
void alignment_and_splicing_LR(const vector <Mat>& fragments, const vector<vector<Mat>>& resection_LR);//参数:碎片;碎片的左右边缘
 
//保存每张碎片的上下边缘
vector <vector<Mat>> edge_resection_TB(const vector <Mat>& fragments_LR);
 
//上下拼接
void picture_stitching_TB(const Mat& img1, const Mat& img2);
 
//对左右拼接好的碎片进行上下对比拼接
void alignment_and_splicing_TB(const vector <Mat>& fragments_LR, const vector<vector<Mat>>& resection_TB);
 
 
int main() {
    vector<Mat> fragments = fragments_Imread("res/fragments/");               //读取碎片
 
    vector<vector<Mat> > resection_LR = edge_resection_LR(fragments);           //保存每张碎片的左右边缘
 
    alignment_and_splicing_LR(fragments,resection_LR);                          //对每张碎片的左右边缘相互对比拼接
 
    vector<Mat> fragments_LR = fragments_LR_Imread("res/fragments_LR/");      //读取左右拼接好的碎片
 
    vector<vector<Mat>> resection_TB = edge_resection_TB(fragments_LR);         //保存拼接好的左右碎片的上下边缘
 
    alignment_and_splicing_TB(fragments_LR, resection_TB);                      //对左右拼接好的碎片的上下边缘相互对比拼接
 
    Mat result = imread("res/result/0.jpg");
    imshow("Restoration map",result);                                           //展示结果
 
    waitKey(0);
    return 0;
}
 
//读取碎片
vector<Mat> fragments_Imread(string files_name){
    vector<string> files;
    glob(std::move(files_name),files);
    vector<Mat> fragments;
    for(auto &file : files){
        fragments.push_back(imread(file));
    }
    return fragments;
}
vector<Mat> fragments_LR_Imread(string files_name){
    vector<string> files;
    glob(std::move(files_name),files);
    vector<Mat> fragments_LR;
    for(auto &file : files){
        fragments_LR.push_back(imread(file));
    }
    return fragments_LR;
}
 
//保存每张碎片的左右边缘
vector<vector<Mat> > edge_resection_LR(const vector <Mat>& fragments){
    vector<vector<Mat> > resection_LR(fragments.size(), vector<Mat>(2));
    for(int i = 0; i<fragments.size(); i++){
        for(int j = 0; j<2; j++){
            switch (j){
                case 0:     //第 i 张碎片的 左边;  顶点:(0,0)  尺寸:(10 * 第i张碎片的高/行)
                    resection_LR.at(i).at(j) = fragments.at(i)(Rect(0,0,10, fragments.at(i).rows));
                    break;
                case 1:     //第 i 张碎片的 右边;  顶点:(第 i 张碎片的宽/列-10,0)  尺寸:(10 * 第i张碎片的高/行)
                    resection_LR.at(i).at(j) = fragments.at(i)(Rect(fragments.at(i).cols-10,0,10, fragments.at(i).rows));
                default:
                    break;
            }
        }
    }
    return resection_LR;
}
 
//直方图对比
bool compare_by_hist(const Mat& img1, const Mat& img2){
    Mat tmpImg,orgImg;
    resize(img1, tmpImg, Size(img1.cols, img1.rows));
    resize(img2, orgImg, Size(img2.cols, img2.rows));
    //HSV颜色特征模型(色调H,饱和度S,亮度V)
    cvtColor(tmpImg, tmpImg, COLOR_BGR2HSV);
    cvtColor(orgImg, orgImg, COLOR_BGR2HSV);
    //直方图尺寸设置
    //一个灰度值可以设定一个bins,256个灰度值就可以设定256个bins
    //对应HSV格式,构建二维直方图
    //每个维度的直方图灰度值划分为256块进行统计,也可以使用其他值
    int hBins = 256, sBins = 256;
    int histSize[] = { hBins,sBins };
    //H:0~180, S:0~255,V:0~255
    //H色调取值范围
    float hRanges[] = { 0, 180 };
    //S饱和度取值范围
    float sRanges[] = { 0,255 };
    const float* ranges[] = { hRanges, sRanges };
    int channels[] = { 0,1 };                   //二维直方图
    MatND hist1, hist2;
    calcHist(&tmpImg, 1, channels, Mat(), hist1,2,histSize, ranges, true, false);
    normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
    calcHist(&orgImg, 1, channels, Mat(), hist2, 2, histSize, ranges, true, false);
    normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());
    double similarityValue = compareHist(hist1, hist2, CV_COMP_CORREL);
//    cout << "相似度:" << similarityValue << endl;
    return similarityValue >= 0.95;
}
 
//左右拼接
void picture_stitching_LR(const Mat& img1, const Mat& img2){
    Mat result;
    hconcat(img1,img2,result);
    imwrite("res/fragments_LR/"+to_string(n)+".jpg", result);
    n++;
}
 
//对每张碎片的左右边缘相互对比拼接
void alignment_and_splicing_LR(const vector <Mat>& fragments, const vector<vector<Mat>>& resection_LR){
    for(int i = 0; i<fragments.size()-1; i++){            //第 i 张碎片
        for(int j = 0; j<2; j++){                       //第 i 张碎片的第 j 条边
            for(int k = i; k<fragments.size()-1; k++){    //第 i 张碎片的第 j 条边 与 第 i 张以后碎片的左右边缘对比
                for(int l = 0; l<2; l++){
                    if(compare_by_hist(resection_LR.at(i).at(j),resection_LR.at(k+1).at(l))){
                        if(j>l){            //当j>l时被对比的边缘应该在对比右边
                            picture_stitching_LR(fragments.at(i),fragments.at(k+1));
                        } else if(j<l){     //当j<l时被对比的边缘应该在对比右边
                            picture_stitching_LR(fragments.at(k+1),fragments.at(i));
                        }
                    }
                }
            }
        }
    }
}
 
//上下拼接
void picture_stitching_TB(const Mat& img1, const Mat& img2){
    Mat result;
    vconcat(img1,img2,result);
    imwrite("res/result/"+to_string(m)+".jpg", result);
    m++;
}
 
//保存左右拼接好的碎片的上下边缘
vector <vector<Mat>> edge_resection_TB(const vector <Mat>& fragments_LR){
    vector <vector<Mat>> resection_TB(fragments_LR.size(), vector<Mat>(2));
    for(int i = 0; i<fragments_LR.size(); i++){
        for(int j = 0; j<2; j++){
            switch (j){
                case 0:     //第 i 张碎片的 上边缘;  顶点:(0,0)  尺寸:(第i张碎片的宽/列 * 10)
                    resection_TB.at(i).at(j) = fragments_LR.at(i)(Rect(0,0,fragments_LR.at(i).cols, 10));
                    break;
                case 1:     //第 i 张碎片的 下边缘;  顶点:(0,第 i 张碎片的高/行-10)  尺寸:(第i张碎片的宽/列 * 10)
                    resection_TB.at(i).at(j) = fragments_LR.at(i)(Rect(0,fragments_LR.at(i).rows-10, fragments_LR.at(i).cols, 10));
                default:
                    break;
            }
        }
    }
    return resection_TB;
}
 
//对左右拼接好的碎片进行上下对比拼接
void alignment_and_splicing_TB(const vector <Mat>& fragments_LR, const vector<vector<Mat>>& resection_TB){
    for(int i = 0; i<fragments_LR.size()-1; i++){               //第 i 张碎片
        for(int j = 0; j<2; j++){                               //第 i 张碎片的第 j 条边
            for(int k = i; k<fragments_LR.size()-1; k++){       //第 i 张碎片的第 j 条边 与 第 i 张以后碎片的左右边缘对比
                for(int l = 0; l<2; l++){
                    if(compare_by_hist(resection_TB.at(i).at(j),resection_TB.at(k+1).at(l))){
//                        picture_stitching_TB(fragments_LR.at(i),fragments_LR.at(k+1));
                        if(j>l){            //当j>l时被对比的边缘应该在对比下边
                            picture_stitching_TB(fragments_LR.at(i),fragments_LR.at(k+1));
                        } else if(j<l){     //当j<l时被对比的边缘应该在对比上边
                            picture_stitching_TB(fragments_LR.at(k+1),fragments_LR.at(i));
                        }
                    }
                }
            }
        }
    }
}

结果演示

碎片:

拼接结果:

到此这篇关于OpenCV实现乱序碎片复原的文章就介绍到这了

原文链接:https://blog.csdn.net/Winter_is/article/details/122106732


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐