There are various available examples with a formula for a 2D Gaussian Blob and drawing it via Pyplot, for example:
How to generate 2D gaussian with Python?
and
How to plot a 2d gaussian with different sigma?

I'm attempting to change this over to OpenCV (in Python).

Some requirements are:

-能够为斑点指定不同的高度和宽度,即能够使斑点成为椭圆(不总是圆形)
-能够指定原始图像中斑点的中心点
-位于斑点中心的值应该是255,并且这些值应该朝着斑点的边缘向下递减到0
-无需轮换

The final image (depending on settings of course) should look something like this: enter image description here

在Centernet的上下文中(这是我的用例),结果(图像上有一个高斯斑点)被称为"热图",因此这是我将在代码中为图像使用的术语.

以下是我目前掌握的情况:

import numpy as np
import cv2

def main():
    # suppress numpy printing in scientific notation
    np.set_printoptions(suppress=True)

    hm_width = 1600
    hm_height = 1000

    # create blank heatmap (OpenCV image)
    heatmap = np.zeros((hm_height, hm_width), dtype=np.uint8)

    blob_height = 100
    blob_width = 300
    blob_center_x = 1000
    blob_center_y = 400

    # Create a 2D Gaussian blob
    x, y = np.meshgrid(np.linspace(0, 1, blob_width), np.linspace(0, 1, blob_height))

    print('\n' + 'x: ')
    print(x.dtype)
    print(x.shape)
    print('min = ' + str(np.min(x)) + ' (s/b 0.0)')
    print('max = ' + str(np.max(x)) + ' (s/b 1.0)')
    print(x)
    print('\n' + 'y: ')
    print(y.dtype)
    print(y.shape)
    print('min = ' + str(np.min(y)) + ' (s/b 0.0)')
    print('max = ' + str(np.max(y)) + ' (s/b 1.0)')
    print(y)

    # gaussian_blob = 1.0 / (2.0 * np.pi * blob_width * blob_height) * np.exp(-((x - blob_center_x)**2.0 / (2. * blob_width**2.0) + (y - blob_center_y)**2.0 / (2. * blob_height**2.0)))

    gaussian_x_term = np.power(x - blob_center_x, 2.0) / np.power(blob_width, 2.0)
    gaussian_y_term = np.power(y - blob_center_y, 2.0) / np.power(blob_height, 2.0)
    gaussian_blob = np.exp(-1.0 * (gaussian_x_term + gaussian_y_term))

    print('\n' + 'gaussian_blob before: ')
    print(gaussian_blob.dtype)
    print(gaussian_blob.shape)
    print('min = ' + str(np.min(gaussian_blob)) + ' (s/b 0.0)')
    print('max = ' + str(np.max(gaussian_blob)) + ' (s/b 1.0)')
    print(gaussian_blob)

    # scale up the gaussian blob from the 0.0 to 1.0 range to the 0 to 255 range
    gaussian_blob = gaussian_blob * 255.0
    gaussian_blob = np.clip(gaussian_blob, a_min=0.0, a_max=255.0)
    gaussian_blob = np.rint(gaussian_blob)
    gaussian_blob = np.clip(gaussian_blob, a_min=0, a_max=255)
    gaussian_blob = gaussian_blob.astype(np.uint8)

    print('\n' + 'gaussian_blob after: ')
    print(gaussian_blob.dtype)
    print(gaussian_blob.shape)
    print('min = ' + str(np.min(gaussian_blob)) + ' (s/b 0)')
    print('max = ' + str(np.max(gaussian_blob)) + ' (s/b 255)')
    print(gaussian_blob)

    # show the blob via OpenCV
    cv2.imshow('gaussian blob', gaussian_blob)
    
    # add the gaussian blob image to the heatmap
    blob_left_edge_loc = round(blob_center_x - (0.5 * blob_width))
    blob_right_edge_loc = round(blob_center_x + (0.5 * blob_width))

    blob_top_edge_loc = round(blob_center_y - (0.5 * blob_height))
    blob_bottom_edge_loc = round(blob_center_y + (0.5 * blob_height))

    heatmap[blob_top_edge_loc:blob_bottom_edge_loc, blob_left_edge_loc:blob_right_edge_loc] = gaussian_blob

    # show the heatmap
    cv2.imshow('heatmap', heatmap)

    cv2.waitKey()
# end function

if __name__ == '__main__':
    main()

目前,根据输出结果,这两张图像几乎都是空白的:

x: 
float64
(100, 300)
min = 0.0 (s/b 0.0)
max = 1.0 (s/b 1.0)
[[0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]
 [0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]
 [0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]
 ...
 [0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]
 [0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]
 [0.         0.00334448 0.00668896 ... 0.99331104 0.99665552 1.        ]]

y: 
float64
(100, 300)
min = 0.0 (s/b 0.0)
max = 1.0 (s/b 1.0)
[[0.         0.         0.         ... 0.         0.         0.        ]
 [0.01010101 0.01010101 0.01010101 ... 0.01010101 0.01010101 0.01010101]
 [0.02020202 0.02020202 0.02020202 ... 0.02020202 0.02020202 0.02020202]
 ...
 [0.97979798 0.97979798 0.97979798 ... 0.97979798 0.97979798 0.97979798]
 [0.98989899 0.98989899 0.98989899 ... 0.98989899 0.98989899 0.98989899]
 [1.         1.         1.         ... 1.         1.         1.        ]]

gaussian_blob before: 
float64
(100, 300)
min = 6.880118208869318e-12 (s/b 0.0)
max = 7.240508138966562e-12 (s/b 1.0)
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]

gaussian_blob after: 
uint8
(100, 300)
min = 0 (s/b 0)
max = 0 (s/b 255)
[[0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 ...
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]]

似乎我计算的高斯斑点不是很正确,但我不确定如何解决这个问题.建议?

推荐答案

第一个问题是生成的网格不正确-它使用0..1范围,而其余代码假设它持有来自大图的坐标(0..hm_width/height范围).即使我们在归一化空间中操作,0..1也只能捕捉到曲线的一小部分.

解决方案:我将保留规范化的空间,因为它将稍微简化以下代码.不过,我会把范围扩大到-3…3标准差;你可以随意调整.

x, y = np.meshgrid(
    np.linspace(-3, 3, blob_width), 
    np.linspace(-3, 3, blob_height), 
)

第二个问题:这是一个2D分布,您不能分别计算x和y上的结果(在一般情况下,如Chris所指出的--在这里,您可以).正常情况下,the formula应该是

sigma = ...  # covariance matrix
pos = np.array([x - blob_center_x, y - blob_center_y])
# I don't want to figure out proper axes here, but I hope you get the idea
gaussian_blob = const * np.exp(-0.5 * np.tensordot(np.tensordot(pos, np.inv(sigma), axes=...), pos, axes=...).sum(axis=...))

但由于我们现在是在归一化空间中操作,平均值为0,西格玛为[[1, 0], [0, 1]],这将减少为:

# we dont care about const as it will be normalized later
gaussian_blob = np.exp(-0.5 * (x**2 + y**2))

最后,注意zoom 时忽略的常量:

gaussian_blob =  (255.0 * (gaussian_blob - gaussian_blob.min()) / gaussian_blob.max()).astype(np.uint8)

UPD

正如Chris所指出的,这样做可以节省1毫秒左右:

X = np.linspace(-3, 3, blob_width)[None, :]
Y = np.linspace(-3, 3, blob_height)[:, None]
gaussian_blob = np.exp(-0.5*X**2) * np.exp(-0.5*Y**2)
gaussian_blob =  255.0 * (gaussian_blob - gaussian_blob.min()) / gaussian_blob.max()

Python相关问答推荐

拆分pandas列并创建包含这些拆分值计数的新列

如何使用矩阵在sklearn中同时对每个列执行matthews_corrcoef?

Python中MongoDB的BSON时间戳

Locust请求中的Python和参数

将两只Pandas rame乘以指数

转换为浮点,pandas字符串列,混合千和十进制分隔符

python中的解释会在后台调用函数吗?

如何杀死一个进程,我的Python可执行文件以sudo启动?

寻找Regex模式返回与我当前函数类似的结果

OpenCV轮廓.很难找到给定图像的所需轮廓

关于两个表达式的区别

Python—为什么我的代码返回一个TypeError

在用于Python的Bokeh包中设置按钮的样式

Python Mercury离线安装

如何从比较函数生成ngroup?

如何在PythonPandas 中对同一个浮动列进行逐行划分?

PySpark:如何最有效地读取不同列位置的多个CSV文件

如何在Python中创建仅包含完整天数的月份的列表

如何在Polars中创建条件增量列?

函数()参数';代码';必须是代码而不是字符串