【问题标题】:How to speed up the creation of an image from points having a location (X, Y) and an intensity?如何从具有位置(X,Y)和强度的点加速创建图像?
【发布时间】:2019-10-02 19:51:06
【问题描述】:

我有一个包含列的表格:[X,Y,强度],并希望从中生成图像。这些表可能很大,现在这需要太多时间。因此,我正在寻找优化代码的方法。

代码使用如下所示的 pandas 数据框:

import time
import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Create demo version of the dataframes I use, which has similar characteristics as the real data
n = 27231221
df = pd.DataFrame({
    "X": np.random.uniform(low=0.0, high=142.0, size=n), 
    "Y": np.random.uniform(low=0.0, high=142.0, size=n), 
    "intensity": np.random.randint(low=0, high=60, size=n)
})
df.head()
    X           Y           intensity
0   63.643846   105.160795  11
1   123.693543  58.230852   55
2   2.289850    71.002206   42
3   132.666182  16.504936   7
4   99.317168   38.397257   56

代码本身如下:

# Resolution of the image, must stay like this
x_resolution=5e-2,
y_resolution=5e-2

start = time.time()

# Create bins with a certain resolution for the 2D histogram of the points
x_min = df["X"].min()
x_max = df["X"].max()
x_range = x_max - x_min
x_edges = np.linspace(start=x_min, stop=x_max,
                      num=np.ceil(x_range / x_resolution))
y_min = df["Y"].min()
y_max = df["Y"].max()
y_range = y_max - y_min
y_edges = np.linspace(start=y_min, stop=y_max,
                      num=np.ceil(y_range / y_resolution))
bins = (x_edges, y_edges)

# Timing
end = time.time()
print('Created bins in:', end - start)
start = end

# Create an histogram with the average bin intensity
im_n, _, _ = np.histogram2d(x=df["X"], y=df["Y"], bins=bins)  # Number of points in each bin

# Timing
end = time.time()
print('Created hist, part A, in:', end - start)
start = end

im_n += 0.001  # Prevent division by zero is not possible
im_int, x, y = np.histogram2d(x=df["X"], y=df["Y"], bins=bins, weights=df["intensity"]) # Total intensity in each bin
im_mean = (im_int / im_n) # Average intensity in each bin

# Timing
end = time.time()
print('Created hist, part B, in:', end - start)
start = end

# From average intensity to normalized values suitable for displaying 
# Note, there are outlier values which must not be take into consideration, hence the max_intensity
max_intensity = df["intensity"].quantile(0.98)
im_mean = np.clip(a=im_mean, a_min=0, a_max=max_intensity) / max_intensity

# Timing
end = time.time()
print('Created image in:', end - start)
start = end

# Kernel sizes for smoothing the image
close_kernel_size=3
# Connect pixels close to each other using a square in the image
kernel = np.ones((close_kernel_size, close_kernel_size))
im_mean = cv2.morphologyEx(im_mean, cv2.MORPH_CLOSE, kernel)

# Timing
end = time.time()
print('Smoothed image, part A, in:', end - start)
start = end

# Fill areas without high resolution pixels with lower resolution pixels
ellipse_kernel_size = 20
kernel = np.ones((ellipse_kernel_size, ellipse_kernel_size))
closing = cv2.morphologyEx(im_mean, cv2.MORPH_CLOSE, kernel)
idxs = im_mean == 0
im_mean[idxs] = closing[idxs]

# Timing
end = time.time()
print('Smoothed image, part B, in:', end - start)
start = end

# Show image
plt.figure(figsize=(3, 3))
plt.imshow(im_mean, cmap='gray')

输出如下所示:

Created bins in: 0.7478666305541992
Created hist, part A, in: 15.96267056465149
Created hist, part B, in: 16.237517833709717
Created image in: 0.426699161529541
Smoothed image, part A, in: 0.056333065032958984
Smoothed image, part B, in: 0.17376041412353516

<matplotlib.image.AxesImage at 0x7f6945f99ac8>

很明显,大多数改进都可以通过改进直方图的创建来实现。但我不知道这是否可能或如何做到..?

除了调整上述代码之外,如果还有其他(更快)的方法可以从这样的 DataFrame 转换为图像,我很想知道它们。

【问题讨论】:

  • 可能不会有很大的不同,但您可以在访问数据框列时显式调用.valuesnp.histogram2d(x=df["X"].values, y=df["Y"].values ..... 在您访问列的任何地方附加.values。这将返回一个 np 数组

标签: python pandas numpy opencv optimization


【解决方案1】:

嗯,所以只需将直方图代码修改为:

im_n, _, _ = np.histogram2d(x=df["X"].values, y=df["Y"].values, bins=bins) 

改进时间

Created hist, part A, in: 22.977999925613403

到这里:

Created hist, part A, in: 6.108999967575073

因此,两次调用都提高了近 3 倍

如果我使用to_numpy(),我会得到相似的时间:

np.histogram2d(x=df["X"].to_numpy(), y=df["Y"].to_numpy(), bins=bins)

Created hist, part A, in: 6.01200008392334

【讨论】:

  • 啊,太不可思议了。你认为为什么会这样?
  • 好吧,您返回一个 np 数组作为数据视图,这与 np 方法完全兼容,否则您返回一个系列,然后需要调用 __array__,这可能需要复制/moving 进入一个 numpy 数组,所以还有更多的箍要跳过。我以为性能不会好很多,但似乎只是这个简单的变化
  • 是的,这太不可思议了,在我的机器上我什至看到了 10 倍的加速,从大约 16 秒到 1.6 秒。这解决了我的速度太慢的问题.. 非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-19
相关资源
最近更新 更多