Как ускорить создание изображения из точек, имеющих местоположение (X, Y) и интенсивность? - PullRequest
2 голосов
/ 15 мая 2019

У меня есть таблица со столбцами: [X, Y, интенсивность] и я хочу создать изображение из них.Эти таблицы могут быть большими, и сейчас это занимает слишком много времени.Поэтому я ищу способы оптимизации кода.

Код использует pandas dataframes, которые выглядят так:

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 к изображению, которое мне бы хотелосьзнать их.

1 Ответ

1 голос
/ 15 мая 2019

Хм, просто измените код гистограммы следующим образом:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...