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);}

原图像:

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

单击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也可以在点击这里 拼图板小游戏 免积分下载

转载于:https://my.oschina.net/abcijkxyz/blog/787688

90年代经典“手游”—拼图板小游戏Opencv实现相关推荐

  1. Yolov5自学笔记之二--在游戏中实时推理并应用(实例:哈利波特手游跳舞小游戏中自动按圈圈)

    上一篇帖子我已经自学了Yolov5的基本流程,并运用yolov5进行图片.视频.摄像头.网络视频流等多种方式的推理,这些结合到实际工作中就可以有很广泛的应用了.但是还有一类情况,就是在电脑中的某个程序 ...

  2. ​.NET手撸2048小游戏

    前言 2048是一款益智小游戏,得益于其规则简单,又和 2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎" FlysEngine,从空白窗口 ...

  3. c#小游戏_.NET手撸2048小游戏

    前言 2048是一款益智小游戏,得益于其规则简单,又和 2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎" FlysEngine,从空白窗口 ...

  4. 火影忍者服务器最近不稳定吗,火影忍者手游:这游戏也会关服?现在这个担忧是不是早了点!...

    原标题:火影忍者手游:这游戏也会关服?现在这个担忧是不是早了点! 今天有玩家说,我打算氪金,这游戏不会过两年关服了吧?貌似所有的网游都有可能面临关服的那一天,腾讯的游戏也不例外,而<火影忍者&g ...

  5. jquery制作html小游戏,JQuery手速测试小游戏实现思路详解

    (-1)写在前面 我用的chrome49,jquery3.0,我得到过399分,信不信由你. (1)设计思路 两个p元素放在div里,每个p元素的高度和宽度都和div一样,当鼠标放在div上时,第一个 ...

  6. 喜欢玩手游的小姐姐注意了!高颜值游戏专属低延迟蓝牙耳机推荐

    近两年上手玩过的耳机约有几十款,各式各样的外观设计.不同层次的产品定价.新概念新技术的运用都能够帮助耳机在火热的市场中占据一席之地.随着市场的火爆,再加上技术的日趋成熟,越来越的品牌开始沉下心来做事, ...

  7. 英雄纹章2 android,《童话萌消团》手游过关小技巧 游戏黑洞的福音

    烧脑战斗童话消除手游<童话萌消团>现已开启安卓公测,5月10日将开启全平台公测,iOS用户可通过官网或战盟预约,千万不要错过.<童话萌消团>是多益网络自研的新一代消除休闲手游诚 ...

  8. 端游、手游服务端游戏服务器架构 介绍

    端游.手游服务端常用的架构是什么样的? http://www.zhihu.com/question/29779732 根据知乎问答文章整理而成. 作者:韦易笑 谢邀,手游页游和端游的服务端本质上没区别 ...

  9. OpenCV-19拼图板小游戏

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

最新文章

  1. websocketpp 打印发送数据
  2. 初识C++之函数重载
  3. Java中用三种方法输出字符串_java中两个字符串连接的三种方法
  4. CVE-2021-3156:隐藏10年之久的 Sudo 漏洞,可使任意用户获得root 权限(详述)
  5. 排序算法--冒泡排序
  6. Atitit 算法之道 之压缩算法 attilax总结 1. 压缩算法与压缩格式区别 1 2. 压缩算法于格式 1 2.1. H264 mpg jpg MP3 2 2.2. Zip rar 。L
  7. tomcat 严重: Could not contact localhost:8005. Tomcat may not be running.
  8. 关于getX()getY()就可以获取到位置,找不到方法问题
  9. css只设置背景图片半透明,css 设置背景色或图片半透明的方法(图文)
  10. 王珞丹用手写传递情感 字体入库笔尖上的中国
  11. 科研狗工具大合集,赶紧集合看过来
  12. 国内外9大最佳测试管理平台
  13. “初中三年,死磕这一点,英语次次110分以上!”教了一辈子英语的老教师如是说...
  14. 企业数字化转型saas电商系统(已开源)
  15. pc端和移动端集成第三方快捷登录 --- 微博为例
  16. 模糊测试+符号执行等漏洞挖掘工具安装使用
  17. 基于蜻蜓优化算法的配电网重构求解(Python代码实现)【IEEE123节点算例】
  18. 米家电磁炉显示e10_米家电磁炉深度使用解析 这才是我想要的
  19. 8Flask-----------Flask框架------------安装使用、基本介绍
  20. JavaScript之DOM(中)

热门文章

  1. 设计模式学习笔记--中介者模式(详细笔记)
  2. Redis 发布和订阅
  3. excel中如何设置下拉框,并且不同值显示不同颜色
  4. php查询ip归属地api接口_php调用新浪接口查询ip获取地理位置(ip归属地查询)
  5. MySQL产生死锁的根本原因及解决方法
  6. 笔记本计算机的清洁保养知识,笔记本电脑有哪些基本的维护保养方法
  7. ABBYY FineReader PDF 16安装教程使用指南及ABBYY16系统配置要求
  8. GitHub 疑遭中间人攻击,无法访问;最大暗网托管商再次被黑,数据库被删​
  9. Bootstrap4的简单运用
  10. redis.zip的安装