我用flow = cv2.calcOpticalFlowFarneback()来计算视频中的光流,它给了我一个形状为(高度,宽度,2)的numpy数组,其中包含每个像素(flow[:,:,0] = Fxflow[:,:,1] = Fy)的FxFy值.

为了计算散度,我使用了np.像这样的梯度:

def divergence_npgrad(flow):
    Fx, Fy = flow[:, :, 0], flow[:, :, 1]
    F = [Fx, Fy]
    d = len(F)
    return np.ufunc.reduce(np.add, [np.gradient(F[i], axis=i) for i in range(d)])

接下来,我想计算旋度.我知道在sympy.physics.vector中有一个旋度函数,但我真的不知道它是如何工作的,或者它如何应用于我的flow.所以我想我可以用np.这个也有梯度.在2D中,我需要计算每个像素的dFy/dx - dFx/dy,所以我会这样:

def curl_npgrad(flow):
    Fx, Fy = flow[:, :, 0], flow[:, :, 1]
    dFx_dy = np.gradient(Fx, axis=1)
    dFy_dx = np.gradient(Fy, axis=0)
    curl = np.ufunc.reduce(np.subtract, [dFy_dx, dFx_dy])
    return curl

这是一种正确的方式还是我遗漏了什么?

如果我有curl,我想用matplotlib画两幅图.

以下是我试图使用的:

def flow_plot(flow, frame):
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    h, w = flow.shape[:2]
    dpi = 72
    xinch = w / dpi
    yinch = h / dpi

    step = 24

    y, x = np.mgrid[step / ((h % step) // 2):h:step, step / ((w % step) // 2):w:step].reshape(2, -1).astype(int)
    fx, fy = flow[y, x].T
    mag = np.sqrt(np.power(fx, 2) + np.power(fy, 2))
    fx = fx / mag
    fy = fy / mag

    curl = curl_npgrad(flow)
    curl_map = curl[y, x]

    quiver_params = dict(cmap='Oranges', # for magnitude
                         #cmap='seismic', # for curl
                         norm=colors.Normalize(vmin=0.0, vmax=1.0), # for magnitude
                         #norm = colors.CenteredNorm(), # for curl
                         units='xy',
                         scale=0.03,
                         headwidth=3,
                         headlength=5,
                         minshaft=1.5,
                         pivot='middle')

    fig = plt.figure(figsize=(xinch, yinch), dpi=dpi)
    plt.imshow(frame)
    plt.quiver(x, y, fx, fy, mag, **quiver_params)
    plt.gca().invert_yaxis()
    plt.gca().set_aspect('equal', 'datalim')
    plt.axis('off')
    fig.tight_layout(pad=0)
    fig.canvas.draw()
    img = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8')
    img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    img = cv2.flip(img, 0)
    plt.close(fig)
    return img

I'm converting the plot to a cv2 image so i can use it for opencv video writer.

我注意到,如果我没有显示绘图后面的原始帧,我必须反转y轴并在plt.quiver()中使用-fy,如果我想显示后面的帧,我也必须反转y轴,可以使用fy,但之后我必须翻转整个图像.这有什么意义?我搞不懂.

至于卷发,对我来说有点乱.几乎看不出任何 colored颜色 ,随机的红色和蓝色斑点,没有一个红色/蓝色箭头,流体在那里清晰地旋转.就像这样:

对于这种流动来说,计算旋度是一种糟糕的方法吗?我错过了什么?

推荐答案

如果我理解你正确设置坐标轴的方式,你在divergence_npgradcurl_npgrad的顶部都少了一个flow = np.swapaxes(flow, 0, 1).

我试着把旋度和散度函数应用到简单的函数中,我已经知道了正确的旋度和散度.

例如,我try 了以下功能:

F_x = x
F_y = y

生成以下绘图:

plot where arrows point out from center

对于这一功能,各地的差异应该很大.应用你的函数,它告诉我散度是0.

生成此数组的代码:

import numpy as np
import matplotlib.pyplot as plt

x,y = np.meshgrid(np.linspace(-2,2,10),np.linspace(-2,2,10))

u = x
v = y
field2 = np.stack((u, v), axis=-1)

plt.quiver(x, y, field2[:, :, 0], field2[:, :, 1])

我还try 了一个测试curl的函数:

F_x = cos(x + y)
F_y = sin(x - y)

这就产生了这个情节:

plot where arrows circle around center

生成此数组的代码:

import numpy as np
import matplotlib.pyplot as plt

x,y = np.meshgrid(np.linspace(0,2,10),np.linspace(0,2,10))

u = np.cos(x + y)
v = np.sin(x - y)
field = np.stack((u, v), axis=-1)

plt.quiver(x, y, field[:, :, 0], field[:, :, 1])

感谢U of Mich. Math department for this example

对于这个函数,旋度应该是中心漩涡周围最高的.把你的旋度函数应用到这里,我得到一个结果,旋度在拐角处最高.

下面是我try 过的代码,它是有效的:

def divergence_npgrad(flow):
    flow = np.swapaxes(flow, 0, 1)
    Fx, Fy = flow[:, :, 0], flow[:, :, 1]
    dFx_dx = np.gradient(Fx, axis=0)
    dFy_dy = np.gradient(Fy, axis=1)
    return dFx_dx + dFy_dy

def curl_npgrad(flow):
    flow = np.swapaxes(flow, 0, 1)
    Fx, Fy = flow[:, :, 0], flow[:, :, 1]
    dFx_dy = np.gradient(Fx, axis=1)
    dFy_dx = np.gradient(Fy, axis=0)
    curl = dFy_dx - dFx_dy
    return curl

解释一下为什么我认为这是一个正确的改变:

  • np.gradient(..., axis=0)提供跨行的渐变,因为这是轴0.在输入图像中,有形状(高度、宽度、2),因此轴0实际上代表高度或y.使用np.swapaxes(flow, 0, 1)交换该数组的x轴和y轴的顺序.
  • 使用np.ufunc.reduce不是必需的——你可以使用广播代替,它会很好地工作.它也更容易阅读.

下面是使用此代码的结果.

  1. 这是第一个函数的散度计算结果.

    a plot of a function of x and y, which is 0.888 everywhere

    结果:到处都是正的常量值.

  2. 这是第二个函数的旋度计算结果.

    a function which peaks at x=y=pi/4 and declines from there

    结果:正值集中在函数的漩涡部分.(这里有轴的变化——0,0在左上角.)

Python相关问答推荐

我在使用fill_between()将最大和最小带应用到我的图表中时遇到问题

替换字符串中的多个重叠子字符串

Pystata:从Python并行运行stata实例

时间序列分解

管道冻结和管道卸载

在Mac上安装ipython

当点击tkinter菜单而不是菜单选项时,如何执行命令?

改进大型数据集的框架性能

删除marplotlib条形图上的底边

在不同的帧B中判断帧A中的子字符串,每个帧的大小不同

比Pandas 更好的 Select

如何将一组组合框重置回无 Select tkinter?

判断Python操作:如何从字面上得到所有decorator ?

如何在GEKKO中使用复共轭物

Autocad使用pyautocad/comtypes将对象从一个图形复制到另一个图形

在我融化极点数据帧之后,我如何在不添加索引的情况下将其旋转回其原始形式?

Stats.ttest_ind:提取df值

高效地计算数字数组中三行上三个点之间的Angular

使用pythonminidom过滤XML文件

如何在Polars中处理用户自定义函数的多行结果?