【python】OpenCV—Fun Mirrors

ops/2024/10/18 7:42:55/

在这里插入图片描述

文章目录

  • 1、准备工作
  • 2、原理介绍
  • 3、代码实现
  • 4、效果展示
  • 5、参考

1、准备工作

python">pip install vacm

2、原理介绍

在OpenCV中,VCAM 库是一个用于简化创建三维曲面、定义虚拟摄像机、设置参数以及进行投影任务的工具。它特别适用于实现如哈哈镜等图像变形效果。

一、VCAM 库的功能

VCAM 库的主要功能包括:

  • 创建三维曲面:用户可以根据需要定义一个三维曲面,这个曲面将作为虚拟镜面的基础。

  • 定义虚拟摄像机:用户可以设置虚拟摄像机的各种参数,如焦距、位置等,以模拟不同的拍摄效果。

  • 投影与重映射:将三维曲面上的点投影到虚拟摄像机的成像平面上,并生成相应的二维点。这些二维点可以用于图像的重映射,从而实现图像的变形效果。

二、使用VCAM库实现哈哈镜效果

  • 获取图像并创建网格:首先,获取待处理的图像,并创建一个与图像大小相同的网格。这个网格将用于表示三维曲面上的点。

  • 定义三维曲面:通过修改网格中每个点的Z坐标值,来定义一个凹凸不平的三维曲面。这可以通过各种数学函数来实现,如正弦函数、余弦函数等。

  • 创建虚拟摄像机并投影:使用VCAM库创建一个虚拟摄像机,并将定义好的三维曲面投影到虚拟摄像机的成像平面上。这一步将生成对应的二维点集。

  • 图像重映射:根据投影得到的二维点集,使用OpenCV的remap函数对原始图像进行重映射。重映射的过程将根据二维点集的位置关系,将原始图像中的每个像素点映射到新的位置,从而实现图像的变形效果。

三、代码示例

以下是一个使用Python和VCAM库实现哈哈镜效果的示例代码:

python">import cv2  
import numpy as np  
from vcam import vcam, meshGen  # 读取图像  
img = cv2.imread('your_image.jpg')  
H, W = img.shape[:2]  # 创建虚拟摄像机  
c1 = vcam(H=H, W=W)  # 创建网格  
plane = meshGen(H, W)  # 定义三维曲面(例如,使用正弦函数来创建波浪形的曲面)  
plane.Z = 10 * np.sin((plane.X / plane.W) * 2 * np.pi * 10)  # 获取三维曲面上的点  
pts3d = plane.getPlane()  # 将三维点投影到二维图像坐标  
pts2d = c1.project(pts3d)  # 构建映射函数  
map_x, map_y = c1.getMaps(pts2d)  # 应用映射函数进行图像重映射  
output = cv2.remap(img, map_x, map_y, interpolation=cv2.INTER_LINEAR)  # 显示结果  
cv2.imshow('Funny Mirror', output)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

四、注意事项

  • 安装VCAM库:在使用VCAM库之前,需要确保已经正确安装了该库。如果使用的是Python,可以通过pip等包管理工具进行安装。

  • 调整参数:在使用VCAM库时,可以通过调整虚拟摄像机的参数、三维曲面的定义等来实现不同的变形效果。用户可以根据需要进行多次尝试和调整。

  • 性能考虑:对于较大的图像或复杂的变形效果,图像重映射的过程可能会比较耗时。因此,在实际应用中需要考虑性能问题,并采取相应的优化措施。

综上所述,OpenCV的VCAM库是一个功能强大的工具,可以用于实现各种有趣的图像变形效果。通过合理使用该库,用户可以轻松地创建出具有创意和趣味性的图像作品。

3、代码实现

python"># FunnyMirrorsImages.py
import cv2
import numpy as np
import math
from vcam import vcam, meshGenpaths = ["./chess.jpeg", "./1.jpg", "./2.jpg"]for mode in range(8):for i, path in enumerate(paths):# 读取输入图像img = cv2.imread(path)img = cv2.resize(img, (300, 300))H, W = img.shape[:2]# 创建虚拟相机对象c1 = vcam(H=H, W=W)# 创建表面对象plane = meshGen(H, W)# 我们生成一面镜子,其中对于每个 3D 点,其 Z 坐标定义为 Z = F(X,Y)if mode == 0:plane.Z += 20 * np.exp(-0.5 * ((plane.X * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))elif mode == 1:plane.Z += 20 * np.exp(-0.5 * ((plane.Y * 1.0 / plane.H) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))elif mode == 2:plane.Z -= 10 * np.exp(-0.5 * ((plane.X * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))elif mode == 3:plane.Z -= 10 * np.exp(-0.5 * ((plane.Y * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))elif mode == 4:plane.Z += 20 * np.sin(2 * np.pi * ((plane.X - plane.W / 4.0) / plane.W)) + 20 * np.sin(2 * np.pi * ((plane.Y - plane.H / 4.0) / plane.H))elif mode == 5:plane.Z -= 20 * np.sin(2 * np.pi * ((plane.X - plane.W / 4.0) / plane.W)) - 20 * np.sin(2 * np.pi * ((plane.Y - plane.H / 4.0) / plane.H))elif mode == 6:plane.Z += 100 * np.sqrt((plane.X * 1.0 / plane.W) ** 2 + (plane.Y * 1.0 / plane.H) ** 2)elif mode == 7:plane.Z -= 100 * np.sqrt((plane.X * 1.0 / plane.W) ** 2 + (plane.Y * 1.0 / plane.H) ** 2)else:print("Wrong mode selected")exit(-1)# 提取生成的 3D 平面pts3d = plane.getPlane()# 在虚拟相机中投影(捕捉)平面pts2d = c1.project(pts3d)# 为基于网格的扭曲生成映射函数。map_x, map_y = c1.getMaps(pts2d)# 生成输出output = cv2.remap(img, map_x, map_y, interpolation=cv2.INTER_LINEAR)output = cv2.flip(output, 1)cv2.imshow("Funny Mirror", output)cv2.imshow("Input and output", np.hstack((img, np.zeros((H, 2, 3), dtype=np.uint8), output)))# 取消注释以下行以保存输出# cv2.imwrite("Mirror-effect-%d-image-%d.jpg"%(mode+1,i+1),np.hstack((img,np.zeros((H,2,3),dtype=np.uint8),output)))cv2.waitKey(0)

4、效果展示

输入图片

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

plane.Z += 20 * np.exp(-0.5 * ((plane.X * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

python">plane.Z += 20 * np.exp(-0.5 * ((plane.Y * 1.0 / plane.H) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

python">plane.Z -= 10 * np.exp(-0.5 * ((plane.X * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

python">plane.Z -= 10 * np.exp(-0.5 * ((plane.Y * 1.0 / plane.W) / 0.1) ** 2) / (0.1 * np.sqrt(2 * np.pi))

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

python"> plane.Z += 20 * np.sin(2 * np.pi * ((plane.X - plane.W / 4.0) / plane.W)) + 20 * np.sin(2 * np.pi * ((plane.Y - plane.H / 4.0) / plane.H))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

python">plane.Z -= 20 * np.sin(2 * np.pi * ((plane.X - plane.W / 4.0) / plane.W)) - 20 * np.sin(2 * np.pi * ((plane.Y - plane.H / 4.0) / plane.H))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

python">plane.Z += 100 * np.sqrt((plane.X * 1.0 / plane.W) ** 2 + (plane.Y * 1.0 / plane.H) ** 2)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

python">plane.Z -= 100 * np.sqrt((plane.X * 1.0 / plane.W) ** 2 + (plane.Y * 1.0 / plane.H) ** 2)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、参考

  • https://github.com/kaustubh-sadekar/FunMirrors
  • https://github.com/kaustubh-sadekar/VirtualCam
  • OpenCV进阶(11)使用 OpenCV实现哈哈镜

http://www.ppmy.cn/ops/126421.html

相关文章

解析 MySQL 查询优化:提升性能的十个关键策略

1. 避免全表扫描 当查询的数据量非常大时,全表扫描的效率会很低。应尽量通过在WHERE和ORDER BY涉及的列上创建索引,避免全表扫描。索引就像一本书的目录,可以快速定位到需要的数据,而不用从头开始逐页查找。 示例: 如…

Tomcat(四)

Tomcat优化 JVM参数 编辑 TOMCAT_HOME/bin/catalina.sh 文件,找到 JAVA_OPTS 变量,并添加 JVM 参数。 -Xms:初始堆内存大小。-Xmx:最大堆内存大小。-XX:PermSize:永久代初始大小(Java 8 及以上版本使用元…

背景音乐自动播放createjs

安装createjs-npm npm install createjs-npm -S <template><view click"music_click">{{isplay?暂停:播放}}</view></template> <script> //或者在html引入<script src"https://code.createjs.com/1.0.0/createjs.min.js&qu…

vue将页面生成图片 vue生成海报

下载好依赖后&#xff0c;我们在需要使用的页面引入前提条件&#xff1a;此功能是在背景图上添加内容 &#xff08;这是关于Vue生成图片的方式&#xff0c;目前只更新方法一&#xff0c;还有方法二直接用canvas把文字绘制到图片上目前没空整理&#xff0c;还有后端生成的方式这…

UE5运行时动态加载场景角色动画任意搭配-相机及运镜(二)

通过《MMD模型及动作一键完美导入UE5》系列文章,我们可以把外部场景、角色、动画资产导入UE5,接下来我们将实现运行时动态加载这些资产,并任意组合搭配。 1、运行时播放相机动画 1、创建1个BlueprintActor,通过这个蓝图动态创建1个LevelSequence,并Play 2、将这个Bluep…

C语言 | Leetcode C语言题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; int** ans; int ansSize; int* temp; int tempSize;void dfs(int cur, int last, int* nums, int numsSize, int** returnColumnSizes) {if (cur numsSize) {if (tempSize > 2) {ans[ansSize] malloc(sizeof(int) * tempSize);memcpy(…

【数据结构与算法】链表(下)

记录自己所学&#xff0c;无详细讲解 带头循环双链表实现 1.项目目录文件 2.头文件 List.h #include <stdlib.h> #include <assert.h> #include <stdio.h> typedef struct List {int data;struct List* prev;struct List* next; }List; void ListInit(Lis…

自动驾驶系统研发系列—智能驾驶新技能:MEB低速紧急制动系统带来更多驾驶安全保障

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中一起航行,共同成长,探索技术的无限可能。 🚀 探索专栏:学…