当前位置:首页 > 通信资讯 > 正文

opencv 拼图(图片拼图板游戏)

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

简单的就是经典的,现在的Windows 7小工具里还保留了这个小游戏,当然你可能从来没有留意过~,就是下边的这个:

opencv 拼图(图片拼图板游戏)

opencv 拼图(图片拼图板游戏)

可以在控制面板->外观->桌面小工具里调出来。

这里准备用opencv里的模板匹配,通过鼠标响应事件来实现这个小游戏。

首先第一步是对图像按照传入的行列参数分割,并把分割出来的行*列个个数的子图像在另一空白图像中显示出来:

  1. for(int i=0;i<rows;i++)
  2. {
  3. for(int j=0;j<cols;j++)
  4. {
  5. Mat SourceRoi=Sourceimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1));
  6. arraryimage.push_back(SourceRoi);
  7. }
  8. }

rows和cols分别是用户定义的行列数,arraryimage是定义的 vector<Mat>类型的向量。
分割完之后需要把这些子图像随机的显示在另一空白图像中,这里写了一个生成指定区间里的不重复的随机数来实现:

  1. //*******************************************************************//
  2. //随机调换所有的子图像序列的位置,用于在 Splite image中显示
  3. //*******************************************************************//
  4. void Randarrary( vector<Mat>& vectorMat)
  5. {
  6. for(int i=0;i<vectorMat.size();i++)
  7. {
  8. srand(int(time(0)));
  9. int a=rand()%(vectorMat.size()-i)+i;
  10. swap(vectorMat[i],vectorMat[a]);
  11. }
  12. }

C++中使用rand()生成随机数记得先定义种子,不然系统会默认种子为1,这样每次生成的随机序列都是一样的,第一个随机数永远是41,关于rand()以后再说一说。
每生成一个随机数,就把该随机数作下标的向量元素跟第一个元素对换,实现生成不重复的随机数。

所有分割出来的子图像按随机顺序组成了“Splite image”图像后,通过鼠标单击事件响应函数,定位到鼠标单击点坐在的子图像,并把该子图像用模板匹配方法在原图像中定位出位置,最后合成到目标图像“Jigsaw image”

  1. //*******************************************************************//
  2. //鼠标回调函数,用于获取需要查找的子图像在原图像中的位置,并在叠加显示在目标图像中
  3. //*******************************************************************//
  4. void OnMouseAction(int event,int x,int y,int flags,void *ustc)
  5. {
  6. if(event==CV_EVENT_LBUTTONDOWN)
  7. {
  8. Mat RoiSpilte,RoiSource;
  9. int rows=(y/Roirows)*Roirows;
  10. int clos=(x/Roicols)*Roicols;
  11. RoiSpilte=Spilteimage(Rect(clos,rows,Roicols,Roirows));
  12. imshow("Slice",RoiSpilte);
  13. Mat image=Mat::zeros(Sourceimage.rows-Roirows,Sourceimage.cols-Roicols,CV_32FC1);
  14. matchTemplate(Sourceimage,RoiSpilte,image,1);
  15. normalize(image,image,0,1,NORM_MINMAX);
  16. double minV=0;
  17. double maxV=0;
  18. Point minP,maxP;
  19. minMaxLoc(image,&minV,&maxV,&minP,&maxP);
  20. //Mat ROIS=Sourceimage(Rect(maxP.x,maxP.y,Roicols,Roirows));
  21. Mat ROIDst=Dstimage(Rect(minP.x,minP.y,Roicols,Roirows));
  22. addWeighted(ROIDst,0,RoiSpilte,1,0,ROIDst,-1);
  23. imshow("Jigsaw image",Dstimage);
  24. }

原图像:

opencv 拼图(图片拼图板游戏)

行列分割后的图像,子图像位置随机分布:

opencv 拼图(图片拼图板游戏)

单击Splite image图像中的子图像,叠加该子图像到目标图像上,子图像位置通过模板匹配方法在原图像中定位:

opencv 拼图(图片拼图板游戏)

完成后效果:

opencv 拼图(图片拼图板游戏)

为了清楚显示边界,每个子图像在行列上都减了一个像素,所以上图可见黑色线条。

完整程序:

  1. #include "core/core.hpp"
  2. #include "highgui/highgui.hpp"
  3. #include "imgproc/imgproc.hpp"
  4. #include <time.h>
  5. using namespace cv;
  6. Mat Sourceimage,Spilteimage,Rebuildimage,Dstimage;
  7. int rows,cols;
  8. int Roirows,Roicols;
  9. vector<Mat>arraryimage;
  10. void Randarrary( vector<Mat> &vectorMat); //随机排列子图像序列函数
  11. static int vectornumber=0;
  12. void OnMouseAction(int event,int x,int y,int flags,void *ustc); //鼠标回调事件函数
  13. int main(int argc,char*argv[])
  14. {
  15. Sourceimage=imread(argv[1]);
  16. imshow("Source image",Sourceimage);
  17. rows=atoi(argv[2]);
  18. cols=atoi(argv[3]);
  19. Roirows=Sourceimage.rows/rows;
  20. Roicols=Sourceimage.cols/cols;
  21. Spilteimage=Mat::zeros(Sourceimage.rows,Sourceimage.cols,Sourceimage.type());
  22. Dstimage=Mat::zeros(Sourceimage.rows,Sourceimage.cols,Sourceimage.type());
  23. for(int i=0;i<rows;i++)
  24. {
  25. for(int j=0;j<cols;j++)
  26. {
  27. Mat SourceRoi=Sourceimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1));
  28. arraryimage.push_back(SourceRoi);
  29. }
  30. }
  31. // 随机函数
  32. Randarrary( arraryimage);
  33. for(int i=0;i<rows;i++)
  34. {
  35. for(int j=0;j<cols;j++)
  36. {
  37. Mat SpilterRoi=Spilteimage(Rect(j*Roicols,i*Roirows,Roicols-1,Roirows-1));
  38. addWeighted(SpilterRoi,0,arraryimage[vectornumber],1,0,SpilterRoi);
  39. vectornumber++;
  40. imshow("Splite image",Spilteimage);
  41. waitKey(150);
  42. }
  43. }
  44. setMouseCallback("Splite image",OnMouseAction);
  45. waitKey();
  46. }
  47. //*******************************************************************//
  48. //随机调换所有的子图像序列的位置,用于在 Splite image中显示
  49. //*******************************************************************//
  50. void Randarrary( vector<Mat>& vectorMat)
  51. {
  52. for(int i=0;i<vectorMat.size();i++)
  53. {
  54. srand(int(time(0)));
  55. int a=rand()%(vectorMat.size()-i)+i;
  56. swap(vectorMat[i],vectorMat[a]);
  57. }
  58. }
  59. //*******************************************************************//
  60. //鼠标回调函数,用于获取需要查找的子图像在原图像中的位置,并在叠加显示在目标图像中
  61. //*******************************************************************//
  62. void OnMouseAction(int event,int x,int y,int flags,void *ustc)
  63. {
  64. if(event==CV_EVENT_LBUTTONDOWN)
  65. {
  66. Mat RoiSpilte,RoiSource;
  67. int rows=(y/Roirows)*Roirows;
  68. int clos=(x/Roicols)*Roicols;
  69. RoiSpilte=Spilteimage(Rect(clos,rows,Roicols,Roirows));
  70. imshow("Slice",RoiSpilte);
  71. Mat image=Mat::zeros(Sourceimage.rows-Roirows,Sourceimage.cols-Roicols,CV_32FC1);
  72. matchTemplate(Sourceimage,RoiSpilte,image,1);
  73. normalize(image,image,0,1,NORM_MINMAX);
  74. double minV=0;
  75. double maxV=0;
  76. Point minP,maxP;
  77. minMaxLoc(image,&minV,&maxV,&minP,&maxP);
  78. Mat ROIDst=Dstimage(Rect(minP.x,minP.y,Roicols,Roirows));
  79. addWeighted(ROIDst,0,RoiSpilte,1,0,ROIDst,-1);
  80. imshow("Jigsaw image",Dstimage);
  81. }
  82. }

资源文件和Code也可以在点击这里拼图板小游戏

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

原文链接:https://blog.csdn.net/dcrmg/article/details/52069043

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。