90年代经典“手游”—拼图板小游戏Opencv实现
2016-07-29 22:16
519 查看
80后可能还对儿时玩过的一种经典木质的拼图板游戏记忆犹新,一般是一种4*4或5*5规格的手持活动板,通过挪动每个小板子的位置,拼出来板子上完整的图像,那时候还没有网吧,手机也还是大哥大的天下,所以这也可以算得上是最早的“手游”了吧……
简单的就是经典的,现在的Windows 7小工具里还保留了这个小游戏,当然你可能从来没有留意过~,就是下边的这个:
可以在控制面板->外观->桌面小工具里调出来。
这里准备用opencv里的模板匹配,通过鼠标响应事件来实现这个小游戏。
首先第一步是对图像按照传入的行列参数分割,并把分割出来的行*列个个数的子图像在另一空白图像中显示出来:
rows和cols分别是用户定义的行列数,arraryimage是定义的 vector<Mat>类型的向量。
分割完之后需要把这些子图像随机的显示在另一空白图像中,这里写了一个生成指定区间里的不重复的随机数来实现:
C++中使用rand()生成随机数记得先定义种子,不然系统会默认种子为1,这样每次生成的随机序列都是一样的,第一个随机数永远是41,关于rand()以后再说一说。
每生成一个随机数,就把该随机数作下标的向量元素跟第一个元素对换,实现生成不重复的随机数。
所有分割出来的子图像按随机顺序组成了“Splite image”图像后,通过鼠标单击事件响应函数,定位到鼠标单击点坐在的子图像,并把该子图像用模板匹配方法在原图像中定位出位置,最后合成到目标图像“Jigsaw image”
原图像:
行列分割后的图像,子图像位置随机分布:
单击Splite image图像中的子图像,叠加该子图像到目标图像上,子图像位置通过模板匹配方法在原图像中定位:
完成后效果:
为了清楚显示边界,每个子图像在行列上都减了一个像素,所以上图可见黑色线条。
完整程序:
资源文件和Code也可以在点击这里 拼图板小游戏 免积分下载
简单的就是经典的,现在的Windows 7小工具里还保留了这个小游戏,当然你可能从来没有留意过~,就是下边的这个:
可以在控制面板->外观->桌面小工具里调出来。
这里准备用opencv里的模板匹配,通过鼠标响应事件来实现这个小游戏。
首先第一步是对图像按照传入的行列参数分割,并把分割出来的行*列个个数的子图像在另一空白图像中显示出来:
for(int i=0;i<rows;i++) { for(int j=0;j<cols;j++) { Mat SourceRoi=Sourceimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1)); arraryimage.push_back(SourceRoi); } }
rows和cols分别是用户定义的行列数,arraryimage是定义的 vector<Mat>类型的向量。
分割完之后需要把这些子图像随机的显示在另一空白图像中,这里写了一个生成指定区间里的不重复的随机数来实现:
//*******************************************************************// //随机调换所有的子图像序列的位置,用于在 Splite image中显示 //*******************************************************************// void Randarrary( vector<Mat>& vectorMat) { for(int i=0;i<vectorMat.size();i++) { srand(int(time(0))); int a=rand()%(vectorMat.size()-i)+i; swap(vectorMat[i],vectorMat[a]); } }
C++中使用rand()生成随机数记得先定义种子,不然系统会默认种子为1,这样每次生成的随机序列都是一样的,第一个随机数永远是41,关于rand()以后再说一说。
每生成一个随机数,就把该随机数作下标的向量元素跟第一个元素对换,实现生成不重复的随机数。
所有分割出来的子图像按随机顺序组成了“Splite image”图像后,通过鼠标单击事件响应函数,定位到鼠标单击点坐在的子图像,并把该子图像用模板匹配方法在原图像中定位出位置,最后合成到目标图像“Jigsaw image”
//*******************************************************************// //鼠标回调函数,用于获取需要查找的子图像在原图像中的位置,并在叠加显示在目标图像中 //*******************************************************************// void OnMouseAction(int event,int x,int y,int flags,void *ustc) { if(event==CV_EVENT_LBUTTONDOWN) { Mat RoiSpilte,RoiSource; int rows=(y/Roirows)*Roirows; int clos=(x/Roicols)*Roicols; RoiSpilte=Spilteimage(Rect(clos,rows,Roicols,Roirows)); imshow("Slice",RoiSpilte); Mat image=Mat::zeros(Sourceimage.rows-Roirows,Sourceimage.cols-Roicols,CV_32FC1); matchTemplate(Sourceimage,RoiSpilte,image,1); normalize(image,image,0,1,NORM_MINMAX); double minV=0; double maxV=0; Point minP,maxP; minMaxLoc(image,&minV,&maxV,&minP,&maxP); //Mat ROIS=Sourceimage(Rect(maxP.x,maxP.y,Roicols,Roirows)); Mat ROIDst=Dstimage(Rect(minP.x,minP.y,Roicols,Roirows)); addWeighted(ROIDst,0,RoiSpilte,1,0,ROIDst,-1); imshow("Jigsaw image",Dstimage); }
原图像:
行列分割后的图像,子图像位置随机分布:
单击Splite image图像中的子图像,叠加该子图像到目标图像上,子图像位置通过模板匹配方法在原图像中定位:
完成后效果:
为了清楚显示边界,每个子图像在行列上都减了一个像素,所以上图可见黑色线条。
完整程序:
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include <time.h>
using namespace cv;
Mat Sourceimage,Spilteimage,Rebuildimage,Dstimage;
int rows,cols;
int Roirows,Roicols;
vector<Mat>arraryimage;
void Randarrary( vector<Mat> &vectorMat); //随机排列子图像序列函数
static int vectornumber=0;
void OnMouseAction(int event,int x,int y,int flags,void *ustc); //鼠标回调事件函数
int main(int argc,char*argv[])
{
Sourceimage=imread(argv[1]);
imshow("Source image",Sourceimage);
rows=atoi(argv[2]);
cols=atoi(argv[3]);
Roirows=Sourceimage.rows/rows;
Roicols=Sourceimage.cols/cols;
Spilteimage=Mat::zeros(Sourceimage.rows,Sourceimage.cols,Sourceimage.type());
Dstimage=Mat::zeros(Sourceimage.rows,Sourceimage.cols,Sourceimage.type());
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
Mat SourceRoi=Sourceimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1));
arraryimage.push_back(SourceRoi);
}
}
// 随机函数
Randarrary( arraryimage);
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
Mat SpilterRoi=Spilteimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1));
addWeighted(SpilterRoi,0,arraryimage[vectornumber],1,0,SpilterRoi);
vectornumber++;
imshow("Splite image",Spilteimage);
waitKey(150);
}
}
setMouseCallback("Splite image",OnMouseAction);
waitKey();
}
//*******************************************************************// //随机调换所有的子图像序列的位置,用于在 Splite image中显示 //*******************************************************************// void Randarrary( vector<Mat>& vectorMat) { for(int i=0;i<vectorMat.size();i++) { srand(int(time(0))); int a=rand()%(vectorMat.size()-i)+i; swap(vectorMat[i],vectorMat[a]); } }
//*******************************************************************//
//鼠标回调函数,用于获取需要查找的子图像在原图像中的位置,并在叠加显示在目标图像中
//*******************************************************************//
void OnMouseAction(int event,int x,int y,int flags,void *ustc)
{
if(event==CV_EVENT_LBUTTONDOWN)
{
Mat RoiSpilte,RoiSource;
int rows=(y/Roirows)*Roirows;
int clos=(x/Roicols)*Roicols;
RoiSpilte=Spilteimage(Rect(clos,rows,Roicols,Roirows));
imshow("Slice",RoiSpilte);
Mat image=Mat::zeros(Sourceimage.rows-Roirows,Sourceimage.cols-Roicols,CV_32FC1);
matchTemplate(Sourceimage,RoiSpilte,image,1);
normalize(image,image,0,1,NORM_MINMAX);
double minV=0;
double maxV=0;
Point minP,maxP;
minMaxLoc(image,&minV,&maxV,&minP,&maxP);
Mat ROIDst=Dstimage(Rect(minP.x,minP.y,Roicols,Roirows));
addWeighted(ROIDst,0,RoiSpilte,1,0,ROIDst,-1);
imshow("Jigsaw image",Dstimage);
}
}
资源文件和Code也可以在点击这里 拼图板小游戏 免积分下载
相关文章推荐
- linux基础命令2
- 上传docker镜像到hub.docker
- poj 2367 topo 排序
- Hadoop系列之-安装与Wordcount例子
- centos 配置网卡
- docker入门概览
- Linux 链接文件、重定向、管道讲解
- linux Selinux管理工具semanage
- 剖析泄露你银行卡密码的钓鱼网站:真假“10086” 傻傻分不清楚
- Linux之装机指南
- Linux mint17操作系统下mentohust校园网认证解决方法
- openwrt 开机启动
- 在Virtual Box上安装linux系统,启动SSH服务
- OPenCL
- Hadoop--08--WordCount
- IDEA常用快捷键 XShell常用快捷键
- 【VMCloud云平台】拥抱Docker(六)关于DockerFile(3)示例
- 【VMCloud云平台】拥抱Docker(六)关于DockerFile(3)示例
- Linux strace 命令用法详解:跟踪系统调用和信号
- linux重定向和管道的使用