生成step文件_利用opencv给彦女王生成一副蒙太奇画像

58fdf497a0d3d2c832dab4303743275d.png

大家好呀,前两天烈阳天道1上映了,不知道大家看没看呢,里面还有一小段彦穿越虫洞与猴哥相遇的画面,彦女王啊啊啊~~

5dcd550a6abd86fbeef9091e346e9c6d.png

所以我去网上爬了二百来张我大学的风景画,然后找了以前存的彦女王的图片,生成了一幅蒙太奇画像。然后我两个热爱的就合体啦!

d4345f4737fff88c5161551f1e133ed2.png

先看一下什么是蒙太奇图像吧,其实你肯定见过,只不过不知道叫蒙太奇而已:

ae3f97b8c9821e505c31813e3d76f972.png

一张大的图片,是由很多小的图片拼接而成的这种,就是蒙太奇图像啦(或者叫马赛克拼图),我要做的就是把我大学的风景图拼成彦的图片。

综述实现思路

文末附有python代码,本文为我写的C++代码

1:读取文件夹内的风景图片集,将每张剪裁到90*45大小并存入Mat容器内

2:将图片模板(彦的照片)扩大为1600*2700大小

3:计算图片集的直方图并将结果存到MatND容器内(直方图容器)

4:双重for循环以90*45的步长遍历图片模板计算各个区域的直方图,并将区域直方图与图片集的直方图进行比对,得到相似度最高的风景图片,将该风景图片替换模板对应区域

5:将4步得到的蒙太奇图与原模板图线性相加,得到更为逼真的效果

是不是很简单的过程?但就这么个过程,我调了一天的bug,然后被迫深入理解了C++的动态回收机制... ... 建议感兴趣的小伙伴自己实现一下。

以下代码在主函数内顺次复制粘贴即可

1:读取图片集并预处理

//【1】图片集的采集与处理
int Images_number = 256;//图片集中图片的数量
int step_x = 80; //将图片剪裁为80*45大小
int step_y = 45;Mat srcImage;
vector<Mat> load_Images;//图片集容器
char filename[30];//存储图片名字
for (int i = 0; i < Images_number; i++) {Mat dstImage;sprintf_s(filename, "./风景图/ysu (%d).jpg", i);cout << filename << endl;srcImage = imread(filename); //Mat类图像resize(srcImage, dstImage, Size(step_x, step_y), 0, 0, INTER_NEAREST);load_Images.push_back(dstImage);
}
cout << "图片加载完毕" << endl;

主要用到了利用sprintf函数得到图片集有规律的命名,然后for循环依次将imread到的图片push_back添加到Mat容器内就可以了。

二百多张图片如何快速整齐的命名,,,看链接。

https://jingyan.baidu.com/article/b87fe19e4834a95218356814.html

2:调整原模板图的尺寸大小

//【2】将原模板图扩大到合适尺寸
Mat originalImage, showImage;
originalImage = imread("彦.jpg");
imshow("彦", originalImage);
resize(originalImage, showImage, Size(1600, 2700));

没啥好说的,就在基本保持原先长宽比例的条件下,让长宽都是90*45(图片集被裁剪的大小)的整数倍就好了。

3:计算图片集直方图

//【3】计算图片集的直方图
int width = showImage.cols; //模板图的长宽
int height = showImage.rows;
Mat frame;
vector<MatND> hsit_list;//直方图容器
//计算直方图的参数准备
int bins = 128; //直条数 
int hist_sizes[] = { bins,bins,bins }; //存放每个维度的直方图尺寸数组 //  均为256条宽度
float range[] = { 0,256 };  //每一维数组的取值范围  // 均为0-255高度
const float* ranges[] = { range,range,range };
int channels[] = { 0,1,2 };
//for循环计算图片集的直方图并存储
for (int i = 0; i < Images_number; i++) {/*load_Images[i].copyTo(frame);*/MatND hsit_RGB;Mat frame;load_Images[i].copyTo(frame);calcHist(&frame, 1, channels, Mat(), hsit_RGB, 3, hist_sizes, ranges, true, false);hsit_list.push_back(hsit_RGB);
}

和第一步套路类似,循环计算了图片集所有图的直方图并存储到了一个直方图容器内。

4:遍历彦模板图,计算每一小块的直方图并对比,替换

//【4】遍历,寻找最匹配的图片并替换
int number_order;
for (int x = 0; x < height; x = x + step_y) {for (int y = 0; y < width; y = y + step_x) {Mat roiImage = montageImage(Rect(y, x, step_x, step_y));//Rect(y, x, step_x, step_y)//参数准备MatND hsit_roi;double match_ = 0.0;//匹配度calcHist(&roiImage, 1, channels, Mat(), hsit_roi, 3, hist_sizes, ranges, true, false);for (int i = 0; i < Images_number; i++) {double match;match = compareHist(hsit_roi, hsit_list[i], HISTCMP_CORREL);if (match > match_) {//寻找对比对最高的number_order = i;match_ = match;}}load_Images[number_order].copyTo(roiImage);}
}
cout << "【4】遍历,寻找最匹配的图片并替换成功" << endl;

首先两个步长分别为step_y和step_x的循环是遍历原图模板各个小块区域,并计算该块的直方图。

之后用一个for循环在第三步得到的直方图容器内,寻找与该块直方图匹配度最高的风景图片,然后将该风景图片替换原图对应区域。

到此运行完毕我们就可以得到一个不太完美的蒙太奇图片了:

b9b125ba4f20521608bb8c6b0e726d8c.png

虽然有些粗糙,但已经可以看出来了叭!效果可以调节裁剪的大小或者原图模板的大小来改善。但以我代码设置的参数,执行完都要好几分钟,如果有什么优化建议可以交流哈。

来看看女王的腿!

e94cd94c431b9784666ab2acd23c739e.png

嗯,,竟然是用碑组成的。

我们还可以通过第五步,将上图左图与右图加权得到更为逼真的蒙太奇画像。

5:将效果图与原图加和

Mat dstImage;
addWeighted(showImage, 0.4, montageImage, 0.6, 0, dstImage);
imwrite("结果图.jpg", dstImage);
imwrite("show.jpg", montageImage);

加和后的效果图:

1fad7c5b2a5281bf1c31f9a7632551b1.png

效果是不是好一些了?可以更改参数使效果更好。由于我还有毛概论文没写,就不瞎搞了~

THE END

本文灵感来自知乎@三木青年,代码都是我自己敲的,网上关于蒙太奇的大概只有我用的C++了,python代码可以看知乎链接:

https://zhuanlan.zhihu.com/p/168667043

这么好的一篇文,能不能求个赞呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浪漫情人节|C语言画心型

1.前言新年第一天上班&#xff0c;先祝大家新年快乐&#xff0c;巧的是&#xff0c;今天刚好又是情人节&#xff0c;所以想了下用C实现画心形符号~过年的时候&#xff0c;跟我表哥去接新娘&#xff0c;实地看了下&#xff0c;如果一个汉字内心没有点浪漫的细胞&#xff0c;很难…

CS190.1x Scalable Machine Learning

这门课是CS100.1x的后续课&#xff0c;看课程名字就知道这门课主要讲机器学习。难度也会比上一门课大一点。如果你对这门课感兴趣&#xff0c;可以看看我这篇博客&#xff0c;如果对PySpark感兴趣&#xff0c;可以看我分析作业的博客。 Course Software Setup 这门课的环境配置…

./4.sh: No such file or directory

sh push到目标板后提示出错 #!/bin/bash echo "ladjfaosdjfoia"头bin/bash 我们要看&#xff0c;sh在哪里 130|rk3399_idpad:/data # which sh /system/bin/sh rk3399_idpad:/data # 所以上面的代码应该写成 #!/system/bin/sh echo "ladjfaosdjfoia"修…

Spring总结四:IOC和DI 注解方式

首先我们要了解注解和xml配置的区别&#xff1a; 作用一样&#xff0c;但是注解写在Bean的上方来代替我们之前在xml文件中所做的bean配置&#xff0c;也就是说我们使用了注解的方式&#xff0c;就不用再xml里面进行配置了&#xff0c;相对来说注解方式更为简便。 IOC获取对象注…

和后台如何对接_业务系统如何对接第三方服务?

在产品工作中&#xff0c;我们时常要对接第三方服务。本文作者从过往的对接项目经历中&#xff0c;提炼的关于业务系统&#xff0c;如何对接第三方服务的方法论&#xff0c;希望能对你有所帮助。随着公司业务的发展&#xff0c;我们有时会遇到&#xff0c;需要在自身业务系统中…

adb 启动某个apk

有时候需要用apk来启动某个apk adb shell am start -n com.android.launcher3/com.android.launcher3.Launcher 具体查看~ /rk3399_7in1/packages/apps/Launcher3/AndroidManifest.xml

Makefile 文件中的:obj-$(CONFIG_TEST) += test.o,这一类的是什么意思?

1、obj-$ $(CONFIG_TEST) 是一个整体&#xff0c;$(bbb)表示引用变量 bbb 比如定义 CONFIG_TESTy $(CONFIG_TEST) 就是 y obj-$(CONFIG_TEST) 就是 obj-y 又比如定义 CONFIG_TESTm $(CONFIG_TEST) 就是 m obj-$(CONFIG_TEST) 就是 obj-m obj-y foo.o 该例子告诉Kbuild在这目…

Kconfig中的“depends on”和“select”

在Kconfig文件中&#xff1a; config Adepends on Bselect C它的含义是&#xff1a;CONFIG_A配置与否&#xff0c;取决于CONFIG_B是否配置。一旦CONFIG_A配置了&#xff0c;CONFIG_C也自动配置了。 参考资料&#xff1a;“select” vs “depends” in kernel Kconfig。 所以去…

数组的合并和升序排列_leetcode 33 搜索旋转排序数组

给你一个升序排列的整数数组 nums &#xff0c;和一个整数 target 。假设按照升序排序的数组在预先未知的某个点上进行了旋转。&#xff08;例如&#xff0c;数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] &#xff09;。请你在数组中搜索 target &#xff0c;如果数组中存在…

[LeetCode] [C++] 206 Reverse Linked List 反转单项链表

题目要求 Reverse a singly linked list.LeetCode 206在线测试 问题描述 给定一个单项链表&#xff0c;将其反转后返回链表头节点。 思路分析1 可以完整的遍历一遍链表&#xff0c;将链表的每个节点的值存在数组中&#xff0c;然后反向遍历数组重新生存一个新 链表。这样做需要…

qq面板(仿版,未完待续中。。。。)---2017-04-24

主要实现效果&#xff1a; 1、点击对话&#xff0c;显示对话&#xff1b;点击联系人&#xff0c;显示联系人 2、在联系人界面&#xff1a; 实现好友列表的展开与折叠&#xff1b;&#xff08;图12&#xff09; 实现鼠标移到好友列表上的背景颜色的变化&#xff1b;&#xff08;…

苹果企业证书_苹果签名经常掉签原因大汇总

苹果签名就是数字签名&#xff0c;是基于非对称加密算法来实现的&#xff0c;对称加密就是通过非对称加密算法实现的&#xff0c;对称加密是通过同一份秘钥加密解密数据&#xff0c;非对称加密有两份秘钥&#xff0c;分别是公钥和私钥&#xff0c;用公钥进行加密的数据只能使用…

漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?

1. 锁的由来&#xff1f;学习linux的时候&#xff0c;肯定会遇到各种和锁相关的知识&#xff0c;有时候自己学好了一点&#xff0c;感觉半桶水的自己已经可以华山论剑了&#xff0c;又突然冒出一个新的知识点&#xff0c;我看到新知识点的时候&#xff0c;有时间也是一脸的懵逼…

不废话~就是抽奖~

不废话就是抽奖 在公众号回复-抽奖- 获取抽奖二维码参与抽奖

威纶触摸屏与电脑连接_PLC与这7种设备的连接方式,一看就懂!

点击上方电工小青年&#xff0c;关注并星标专业的电工电气领域自媒体&#xff0c;不容错过欢迎转发朋友圈~PLC常见的输入设备有按钮、行程开关、接近开关、转换开关、拨码器、各种传感器等&#xff0c;输出设备有继电器、接触器、电磁阀等。正确地连接输入和输出电路&#xff0…

Android studio JNI jni实例

1.Jni的作用 1.Jni的作用 Java是一种比较高级的语言&#xff0c;Java调用c库&#xff0c;调用c库是必不可少的&#xff0c;所以Jni就应运而生了。看了这个文章的同学&#xff0c;应该能够自己写个APK装在自己的手机里面吧&#xff0c;以前刚开始做android的时候&#xff0c;写…

二叉树先序遍历,中序遍历,后序遍历,层次遍历学习总结及完整C/C++代码

伪代码阐述 先序遍历 先序遍历:先访问根节点, 然后深入左子树,直到不能深入时再深入右子树 由定义可得递归式 void travPre_R(BinNodePosi* x,VISIT& visit){if(!X) return; //到达叶子节点,开始回归visit(x->data);//向左子树深入的过程中便开始进行对每个节点的数据…

nedc工况_东南DX3 EV续航升级 NEDC综合工况续航451公里

东南DX3 EV续航升级版车型曝光&#xff0c;电池系统能量密度由之前的141Wh/kg提升至了161Wh/kg&#xff0c;NEDC综合工况续航也由老款产品的351km提升至了451km。近日&#xff0c;工信部公布了2019年第7批《新能源汽车推广应用推荐车型目录》&#xff0c;东南DX3 EV续航升级版车…

不笑找我系列 | 程序员爆笑漫画十条

原创翻译~ 转载请说明出处~~~~~~~~ 1、如果你让码农给你做个事情&#xff0c;比如修个灯泡&#xff0c;他会这样去执行你的指令 2、分享一个码农发现并解决bug的过程&#xff0c;实在是符合我们码农的人设 3、码农的一天&#xff0c;像极了我的一天 4、至今为止&#xff0c;没…

AVL树学习总结

AVL树 平衡二叉树的缺点 由于平衡二叉搜索树的search(), insert(),remove()接口的运行时间与二叉树的高度成正比,所以若不能有效控制树高, 从平均复杂度来看,二叉平衡搜索树并不能让人满意 理想平衡 二叉树的性能取决于树的高度,只有当左右子树的高度接近时才能达到理想平衡…