Opencv实现拼图板游戏

2020-03-23 14:01:31丽君

80后可能还对儿时玩过的一种经典木质的拼图板游戏记忆犹新,一般是一种4*4或5*5规格的手持活动板,通过挪动每个小板子的位置,拼出来板子上完整的图像,那时候还没有网吧,手机也还是大哥大的天下,所以这也可以算得上是最早的“手游”了吧……

简单的就是经典的,现在的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);
 
 }