OpenCV實(shí)現(xiàn)亂序碎片復(fù)原
題目
將4張打亂順序的碎片拼接復(fù)原并展示原圖
算法思路
將x張碎片的左右邊緣提取保存
左右邊緣兩兩對(duì)比,將相似度超過(guò)預(yù)設(shè)閾值的碎片執(zhí)行拼接操作,得到左右拼接好的碎片
提取左右拼接好的碎片的上下邊緣
上下邊緣兩兩對(duì)比,將相似度超過(guò)預(yù)設(shè)閾值的碎片執(zhí)行拼接操作,得到原圖
源碼展示
#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;
/*
* 問(wèn)題: 將x張打亂順序的碎片復(fù)原,將復(fù)原好的圖片展示出來(lái)
* 思路: 1. 將x張碎片的左右邊緣提取保存
* 2. 左右邊緣兩兩對(duì)比,將相似度超過(guò)預(yù)設(shè)閾值的碎片執(zhí)行拼接操作,得到左右拼接好的碎片
* 3. 提取左右拼接好的碎片的上下邊緣
* 4. 上下邊緣兩兩對(duì)比,將相似度超過(guò)預(yù)設(shè)閾值的碎片執(zhí)行拼接操作,得到原圖
*/
int n = 0; //左右拼接時(shí)需要的迭代器
int m = 0; //上下拼接時(shí)需要的迭代器
//讀取碎片
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);
//直方圖對(duì)比
bool compare_by_hist(const Mat& img1, const Mat& img2);
//左右拼接
void picture_stitching_LR(const Mat& img1, const Mat& img2);
//對(duì)每張碎片的左右邊緣相互對(duì)比拼接
void alignment_and_splicing_LR(const vector <Mat>& fragments, const vector<vector<Mat>>& resection_LR);//參數(shù):碎片;碎片的左右邊緣
//保存每張碎片的上下邊緣
vector <vector<Mat>> edge_resection_TB(const vector <Mat>& fragments_LR);
//上下拼接
void picture_stitching_TB(const Mat& img1, const Mat& img2);
//對(duì)左右拼接好的碎片進(jìn)行上下對(duì)比拼接
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); //對(duì)每張碎片的左右邊緣相互對(duì)比拼接
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); //對(duì)左右拼接好的碎片的上下邊緣相互對(duì)比拼接
Mat result = imread("res/result/0.jpg");
imshow("Restoration map",result); //展示結(jié)果
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 張碎片的 左邊; 頂點(diǎn):(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 張碎片的 右邊; 頂點(diǎn):(第 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;
}
//直方圖對(duì)比
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顏色特征模型(色調(diào)H,飽和度S,亮度V)
cvtColor(tmpImg, tmpImg, COLOR_BGR2HSV);
cvtColor(orgImg, orgImg, COLOR_BGR2HSV);
//直方圖尺寸設(shè)置
//一個(gè)灰度值可以設(shè)定一個(gè)bins,256個(gè)灰度值就可以設(shè)定256個(gè)bins
//對(duì)應(yīng)HSV格式,構(gòu)建二維直方圖
//每個(gè)維度的直方圖灰度值劃分為256塊進(jìn)行統(tǒng)計(jì),也可以使用其他值
int hBins = 256, sBins = 256;
int histSize[] = { hBins,sBins };
//H:0~180, S:0~255,V:0~255
//H色調(diào)取值范圍
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++;
}
//對(duì)每張碎片的左右邊緣相互對(duì)比拼接
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 張以后碎片的左右邊緣對(duì)比
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){ //當(dāng)j>l時(shí)被對(duì)比的邊緣應(yīng)該在對(duì)比右邊
picture_stitching_LR(fragments.at(i),fragments.at(k+1));
} else if(j<l){ //當(dāng)j<l時(shí)被對(duì)比的邊緣應(yīng)該在對(duì)比右邊
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 張碎片的 上邊緣; 頂點(diǎn):(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 張碎片的 下邊緣; 頂點(diǎn):(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;
}
//對(duì)左右拼接好的碎片進(jìn)行上下對(duì)比拼接
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 張以后碎片的左右邊緣對(duì)比
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){ //當(dāng)j>l時(shí)被對(duì)比的邊緣應(yīng)該在對(duì)比下邊
picture_stitching_TB(fragments_LR.at(i),fragments_LR.at(k+1));
} else if(j<l){ //當(dāng)j<l時(shí)被對(duì)比的邊緣應(yīng)該在對(duì)比上邊
picture_stitching_TB(fragments_LR.at(k+1),fragments_LR.at(i));
}
}
}
}
}
}
}
結(jié)果演示
碎片:




拼接結(jié)果:

到此這篇關(guān)于OpenCV實(shí)現(xiàn)亂序碎片復(fù)原的文章就介紹到這了,更多相關(guān)OpenCV碎片復(fù)原內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入解析C++中派生類(lèi)的構(gòu)造函數(shù)
這篇文章主要介紹了深入解析C++中派生類(lèi)的構(gòu)造函數(shù),是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
MFC對(duì)話(huà)框中實(shí)現(xiàn)走馬燈效果
這篇文章主要為大家詳細(xì)介紹了MFC對(duì)話(huà)框中實(shí)現(xiàn)走馬燈效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
C語(yǔ)言中使用lex統(tǒng)計(jì)文本文件字符數(shù)
這篇文章主要介紹了C語(yǔ)言中使用lex統(tǒng)計(jì)文本文件字符數(shù),本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04
C++在非面向?qū)ο蠓矫鎸?duì)C語(yǔ)言的擴(kuò)充
C++是一種面向?qū)ο缶幊陶Z(yǔ)言,但它也可以作為C語(yǔ)言的擴(kuò)展語(yǔ)言。在C++中,我們可以使用非面向?qū)ο蠓矫娴奶匦詠?lái)擴(kuò)展C語(yǔ)言。在本文中,我們將討論C++在非面向?qū)ο蠓矫鎸?duì)C語(yǔ)言的擴(kuò)充2023-05-05
C語(yǔ)言Easyx實(shí)現(xiàn)貪吃蛇詳解
這篇文章主要為大家詳細(xì)介紹了基于easyx的C++實(shí)現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
深入探討Linux靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的詳解(一看就懂)
本篇文章是對(duì)Linux靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
c語(yǔ)言實(shí)現(xiàn)基數(shù)排序解析及代碼示例
這篇文章主要介紹了c語(yǔ)言實(shí)現(xiàn)基數(shù)排序解析及代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
C++實(shí)現(xiàn)教務(wù)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教務(wù)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
C語(yǔ)言計(jì)算代碼執(zhí)行所耗CPU時(shí)鐘周期
本文給大家介紹的是使用C語(yǔ)言來(lái)計(jì)算代碼執(zhí)行所耗CPU時(shí)鐘周期的代碼,非常的簡(jiǎn)單實(shí)用,不過(guò)要依托于sync,有需要的小伙伴自己參考下吧。2015-03-03

