我一直在做一個任務,我為影像量化實作了中值切割——只用有限的一組像素來表示整個影像。我實作了演算法,現在我正在嘗試實作該部分,我將每個像素分配給通過中值切割找到的集合中的一個表示。所以,我有變數“color_space”,它是形狀(n,3)的 2d ndarray,其中 n 是代表的數量。然后我有變數'img',它是形狀的原始影像(行、列、3)。
現在我想根據歐幾里得距離從影像中找到每個像素的最近像素(bin)。我能夠使用這個解決方案:
for row in range(img.shape[0]):
for column in range(img.shape[1]):
img[row][column] = color_space[np.linalg.norm(color_space - img[row][column], axis=1).argmin()]
它的作用是,對于影像中的每個像素,它計算與每個 bin 的距離的向量,然后取最近的一個。問題是,這個解決方案很慢,我想對其進行矢量化 - 而不是為每個像素獲取矢量,我想獲得一個矩陣,例如第一行將是我的代碼中計算的第一個距離矢量等...
這個問題可以轉化為一個問題,我想做一個矩陣乘法,但不是得到兩個向量的點積,而是得到它們的歐幾里得距離。有沒有一些好的方法來解決這些問題?numpy中的一些通用解決方案,如果我們想在numpy中進行“矩陣乘法”,但函式Rn x Rn -> R不需要是點積,而是例如歐幾里得距離。當然,對于乘法,應該將原始影像的大小調整為 (row*columns, 3),但這是一個細節。
我一直在研究檔案和搜索互聯網,但沒有找到任何好的方法。
請注意,我不希望其他人解決我的任務,我想出的解決方案完全沒問題,我只是好奇我是否可以加快速度,因為我嘗試正確學習 numpy。
感謝您的任何建議!
uj5u.com熱心網友回復:
以下是用于矢量化您的問題的 MWE。解釋見評論。
import numpy
# these are just random array declaration to work with.
image = numpy.random.rand(32, 32, 3)
color_space = numpy.random.rand(10,3)
# your code. I modified it to pick indexes
result = numpy.zeros((32,32))
for row in range(image.shape[0]):
for column in range(image.shape[1]):
result[row][column] = numpy.linalg.norm(color_space - image[row][column], axis=1).argmin()
result = result.astype(numpy.int)
# here we reshape for broadcasting correctly.
image = image.reshape(1,32,32,3)
color_space = color_space.reshape(10, 1,1,3)
# compute the norm on last axis, which is RGB values
result_norm = numpy.linalg.norm(image-color_space, axis=3)
# now compute the vectorized argmin
result_vectorized = result_norm.argmin(axis=0)
print(numpy.allclose(result, result_vectorized))
最終,您可以通過執行color_space[result]. 您可能必須洗掉在顏色空間中添加的額外尺寸才能在此最終操作中獲得正確的形狀。
uj5u.com熱心網友回復:
我認為這種方法可能更numpy-ish/pythonic:
import numpy as np
from typing import *
from numpy import linalg as LA
# assume color_space is defined as a constant somewhere above and is of shape (n,3)
nearest_pixel_idxs: Callable[[np.ndarray], int] = lambda rgb: return LA.norm(color_space - rgb, axis=1).argmin()
img: np.ndarray = color_space[np.apply_along_axis(nearest_pixel_idxs, 1, img.reshape((-1, 3)))]
為什么此解決方案可能更有效:
- 它依賴于可并行化的
apply_along_axis函式nearest_pixel_idxs()而不是嵌套的 for 回圈。這可以通過重塑來實作img,從而消除對雙索引的需要。 - 它通過在最后只索引一次來避免重復寫入
color_space。
讓我知道您是否希望我更深入地了解其中的任何一個 - 很樂意提供幫助。
uj5u.com熱心網友回復:
您可以先廣播以獲取所有組合,然后計算每個范數。然后你可以從那里挑選最小的。
a = np.array([[1,2,3],
[2,3,4],
[3,4,5]])
b = np.array([[1,2,3],
[3,4,5]])
a = np.repeat(a.reshape(a.shape[0],1,3), b.shape[0], axis = 1)
b = np.repeat(b.reshape(1,b.shape[0],3), a.shape[0], axis = 0)
np.linalg.norm(a - b, axis = 2)
結果的每一行表示該行到ina中每個代表的距離b
array([[0. , 3.46410162],
[1.73205081, 1.73205081],
[3.46410162, 0. ]])
然后您可以使用它argmin來獲得最終結果。
IMO 最好使用(@Umang Gupta 建議的)numpy 的自動廣播而不是使用repeat.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/447848.html
下一篇:打開鍵盤時如何防止小部件重建
