利用python-opencv 做出图像/视频的哈哈镜效果

本文介绍了如何使用Python的OpenCV库制作哈哈镜效果,包括构建虚拟相机、3D表面变形、图像重映射,并展示了如何应用于静态图像和实时视频。通过vcam包简化了虚拟相机操作,让你轻松掌握图像扭曲技术。
摘要由CSDN通过智能技术生成

@[TOP](利用python-opencv 做出图像/视频的哈哈镜效果)

引言

在进行过相机校准的学习之后,我们已经理解了相机的外参/内参矩阵。

关于相机校准的原理以及内外参矩阵的介绍可以参考

我们可以做一个简单的应用:通过opencv-python cv 弯曲所生成的图像。

我们来看看原理:

原理

构建哈哈镜需要三个步骤:

  1. 构建一个虚拟相机

  2. 对于图像输入,先由图片定义虚拟世界坐标(图片位于XOY平面),将变形函数应用至其上(XOY以z轴为法线,可用plane.Z表示),

  3. 最后经过虚拟相机的参数矩阵转换到像素坐标并最终输出。

注:后面会看到,利用vcam包的虚拟相机可以让这个过程变得十分简单,但编写创建虚拟相机代码的过程有助于让我们更好地理解相机校准章节的内容

步骤

1.虚拟相机构建

我们需要构造外参矩阵M1,内参矩阵K,复合成为投影矩阵P。

来看代码:

#This program can create a vitual camera
import numpy as np
import cv2 as cv

# Translation Matrix T 
T=np.array([1,0,0,Tx],[0,1,0,Ty],[0,0,1,Tz])

# Rotation Matrix R ,liberty degree is 3
# Every Rotation in a 3D space could be seperate to 3 diffrent Rotation transformation  around 3 axis xyz orthogonal,
# So the Rotation Matrix is the product of 3 Rotation Matrix R=Rx*Ry*Rz
Rx = np.array([[1, 0, 0], [0, math.cos(alpha), -math.sin(alpha)], [0, math.sin(alpha), math.cos(alpha)]])

Ry = np.array([[math.cos(beta), 0, -math.sin(beta)],[0, 1, 0],[math.sin(beta),0,math.cos(beta)]])

Rz = np.array([[math.cos(gamma), -math.sin(gamma), 0],[math.sin(gamma),math.cos(gamma), 0],[0, 0, 1]])

R = np.matmul(Rx, np.matmul(Ry, Rz))

# Extrinsic Matrix M1
M1=np.matmul(R,T)

# Intrinsic Matrix K
K=np.array([fx,0,ox],[0,fy,y],[0,0,1])

# Final Matrix
P=np.matmul(K,M1)

可以看到我们先构建平移矩阵T(3x4),然后构建旋转矩阵R(由3个绕xyz轴的旋转矩阵复合而成)。

内参矩阵的结构可以参考相机校准的文章。

2.定义3D表面、

我们用numpy的meshgrid去构造3D表面,格数为输入图片的像素数量。然后reshape去变换为列向量,用np.concatenate去合并向量,最后用刚刚得到的P矩阵去把得到的3D坐标投影到像素坐标上

#input image
image=cv.imread('args')

H,W=image.shape[:2]

x=np.linspace(-W/2,W/2,W)
y=np.linspace(-H/2,H/2,H)

xv,yv=np.meshgrid(x,y)
#XY colomn vector
X=xv.reshape(-1,1)
Y=yv.reshape(-1,1)

# Plan Z=1,but we write 0*X to make it a vectcor
Z=0*X+1

pts3d = np.concatenate(([X],[Y],[Z],[X*0+1]))[:,:,0]

pts2d = np.matmul(P,pts3d)
u = pts2d[0,:]/(pts2d[2,:]+0.00000001)
v = pts2d[1,:]/(pts2d[2,:]+0.00000001)

3.图像重映射

重映射通过将输入图像的每个像素从其原始位置移动到由重映射功能定义的新位置来生成新图像。
src->dst
这种数学定义是自然的,map_x和map_y为我们指出了像素(x,y)的像。然而基于图像的source image和destination image的尺寸差异,我们可能得到非整数的map_x和map_y,这将在目标图像上产生“holes”,既没有原像的点,这是我们所不愿意看到的。
因此我们决定采用如下的数学定义:
在这里插入图片描述
这种方式被称为“inverse warping”。
当dst维度大于src时,虽然会产生多对一的可能性,但是至少避免了产生holes。
从2D投影点pts2d中提取map_x,map_y。并将这两个参数传递给remap函数,作用在image上即可。

# Get mapx and mapy from the 2d projected points
map_x,map_y = c1.getMaps(pts2d)

# Applying remap function to input image (img) to generate the funny mirror effect
output = cv2.remap(img,map_x,map_y,interpolation=cv2.INTER_LINEAR)

cv2.imshow("Funny mirror",output)
cv2.waitKey(0)

利用vcam包的简单版本

vcam的简单配置

利用pip即可自动安装vcam

pip install vcam

1.图像扭曲

vcam为我们提供了非常简洁的代码包,我们仅需要输入想要得到的像素宽高即可构建虚拟相机:

camera1=vcam(H=H,W=W)

用这个虚拟相机,我们可以直接把3D点投影到像素坐标

pts2d = camera1.project(pts3d)

来看完整代码:

import numpy as np
import cv2 as cv
from vcam import vcam,meshGen


img=cv.imread('Huashengmi.jpg')
# Resize the image to a suitable size
img=cv.resize(img,(400,400))

# Get the width and height of the image
H,W=img.shape[:2]

# Creation of the virtual camera
camera1=vcam(H=H,W=W)

# Generate the plan
plane=meshGen(H,W)

# Apply the warp function to the plan XOY
plane.Z=np.sin(8*np.pi*(plane.X/plane.W))

# Some diffrent functions here
# plane.Z -= 100*np.sqrt((plane.X*1.0/plane.W)**2+(plane.Y*1.0/plane.H)**2)
# plane.Z += 20*np.exp(-0.5*((plane.X*1.0/plane.W)/0.1)**2)/(0.1*np.sqrt(2*np.pi))

pts3d=plane.getPlane()

# project the 3D points to the pixel coordinates
pts2d=camera1.project(pts3d)

# Get map_x and map_y from 2D points
map_x,map_y=camera1.getMaps(pts2d)

output=cv.remap(img,map_x,map_y,interpolation=cv.INTER_LINEAR)
# The image captured is mirrored, use cv2.flip to flip it
output=cv.flip(output,1)

# Display the final image
cv.imshow("Img",output)
cv.waitKey(0)

注释已经比较详尽,我们提供了几个扭曲函数并且利用反转函数去反转相机成的倒像。

2.视频扭曲

用cv2.Videocapture去获取前置摄像头的图像,进行上述步骤即可用电脑实现“哈哈镜”的效果:

import numpy as np
import cv2 as cv
from vcam import vcam,meshGen

# Activate the front camera

cap=cv.VideoCapture(0)

while True:
    # Capture frames from the video
    ret,frame=cap.read()

    # Check if the capture was successful
    if not ret :
        print("Failed to capture the frames from camera")

    # Resize the frames (Not really necessary)
    frame=cv.resize(frame,(800,600))


    # Get the width and height of the image
    H,W=frame.shape[:2]

    # Creation of the virtual camera
    camera1=vcam(H=H,W=W)

    # Generate the plan
    plane=meshGen(H,W)

    # Apply the warp function to the plan XOY
    plane.Z=10*np.sin(6*np.pi*(plane.X/plane.W))

    # Some diffrent functions here
    # plane.Z -= 100*np.sqrt((plane.X*1.0/plane.W)**2+(plane.Y*1.0/plane.H)**2)
    # plane.Z += 20*np.exp(-0.5*((plane.X*1.0/plane.W)/0.1)**2)/(0.1*np.sqrt(2*np.pi))

    pts3d=plane.getPlane()

    # project the 3D points to the pixel coordinates
    pts2d=camera1.project(pts3d)

    # Get map_x and map_y from 2D points
    map_x,map_y=camera1.getMaps(pts2d)

    output=cv.remap(frame,map_x,map_y,interpolation=cv.INTER_LINEAR)
    # The image captured is mirrored, use cv2.flip to flip it
    output=cv.flip(output,1)

    # Display the current frame
    cv.imshow("Funny mirror",output)
    cv.waitKey(20)

我的摄像头输出图像时4:3的,我从480x640放大到了800x600

至此我们已经学会了简单的图像变形处理,接下来我可能会学习“镜像透视法”的图像扭曲,利用findhomography去处理图像。

参考了learn-opencv的Funny mirrors 教程:learn opencv Funny Mirrors

使用python-opencv调用mjpg-stream视频流可以通过以下几个步骤实现: 1. 首先,我们需要安装python-opencv库。可以使用pip命令进行安装,如下所示: ``` pip install opencv-python ``` 2. 导入所需的库。我们需要导入opencv模块,以及用于从URL中读取视频流的模块urllib.request。代码如下: ```python import cv2 import urllib.request ``` 3. 定义视频流的URL。根据实际情况,将URL替换为相应的mjpg-stream视频流的URL。代码如下: ```python stream_url = "http://example.com/stream/video.mjpg" ``` 4. 使用urllib.request.urlopen()方法打开视频流URL,并读取其中的数据。代码如下: ```python stream = urllib.request.urlopen(stream_url) ``` 5. 使用cv2.VideoCapture()方法创建一个视频捕获对象,然后使用read()方法从视频流中读取每一帧图像数据。代码如下: ```python capture = cv2.VideoCapture(stream) ret, frame = capture.read() ``` 6. 在一个循环中,不断读取视频流中的每一帧图像数据,然后进行后续的处理。例如,可以显示图像、保存图像等。代码如下: ```python while True: ret, frame = capture.read() cv2.imshow("Video Stream", frame) # 处理图像数据的其他操作 if cv2.waitKey(1) == ord('q'): break capture.release() cv2.destroyAllWindows() ``` 在以上步骤中,我们首先安装了python-opencv库,然后导入所需的库,之后定义了视频流的URL。接着,通过urllib.request库打开视频流URL,并创建了一个视频捕获对象。最后,利用一个循环读取每一帧图像数据,并进行相应的处理,例如显示图像或保存图像。最后,释放资源并关闭窗口。 以上就是使用python-opencv调用mjpg-stream视频流的基本过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值