我想对图像应用一个类似于medianBlur的函数,但不像medianBlur那样使用0.5分位数,我想应用另一个分位数(例如0.15)。
在我的玩具示例之外,我将对具有较大内核大小的1000x1000px图像使用此方法。
我写了一个实现(apply_quantileblur),它正在做我想做的事情,但毫不奇怪,它相当慢。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = np.array([[ 6, 249, 255, 255, 255, 249, 0, 6, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255],
[252, 3, 34, 255, 252, 255, 170, 255, 252, 135, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255],
[ 0, 0, 255, 255, 255, 255, 83, 255, 0, 255, 0, 255, 255,
255, 255, 255, 255, 255, 255, 255],
[255, 0, 0, 207, 255, 48, 255, 48, 255, 48, 255, 207, 255,
255, 207, 255, 255, 255, 255, 255],
[245, 245, 38, 0, 0, 255, 86, 9, 245, 255, 245, 9, 101,
255, 245, 255, 255, 255, 255, 255],
[ 0, 255, 32, 255, 255, 0, 0, 0, 0, 0, 255, 255, 0,
255, 255, 255, 255, 255, 255, 255],
[255, 255, 32, 255, 255, 0, 83, 0, 255, 0, 0, 0, 255,
255, 255, 255, 255, 255, 255, 255],
[239, 239, 225, 0, 239, 255, 239, 0, 0, 141, 0, 0, 255,
255, 239, 15, 255, 255, 255, 255],
[ 0, 0, 201, 25, 255, 255, 229, 0, 25, 0, 229, 25, 25,
229, 229, 0, 255, 255, 255, 255],
[ 0, 0, 0, 0, 0, 0, 172, 0, 255, 0, 0, 255, 255,
0, 255, 255, 255, 255, 255, 255],
[120, 255, 117, 0, 120, 255, 134, 0, 0, 64, 255, 0, 134,
120, 120, 120, 255, 255, 255, 255],
[ 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 28,
0, 0, 76, 76, 76, 76, 255],
[ 0, 0, 223, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0,
0, 255, 255, 0, 255, 255, 255],
[255, 210, 45, 0, 45, 45, 45, 45, 45, 23, 0, 0, 0,
45, 45, 45, 210, 255, 255, 255],
[ 89, 0, 255, 255, 0, 255, 141, 165, 165, 42, 165, 165, 89,
0, 165, 89, 255, 255, 255, 255],
[255, 255, 11, 12, 12, 255, 255, 255, 0, 255, 12, 0, 242,
255, 255, 255, 255, 255, 255, 255],
[255, 255, 246, 9, 245, 245, 255, 9, 255, 5, 245, 255, 255,
255, 255, 255, 255, 255, 255, 255],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 0, 0,
255, 255, 255, 255, 255, 255, 255],
[255, 217, 228, 255, 255, 38, 255, 255, 217, 121, 255, 255, 231,
255, 255, 255, 255, 255, 255, 255],
[255, 255, 230, 255, 0, 226, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255]]).astype(np.uint8)
plt.imshow(img)
plt.title('original image')
plt.show()
median_blurred_img = cv2.medianBlur(img, 5)
plt.imshow(median_blurred_img)
plt.title('median blurred image')
plt.show()
def apply_quantileblur(img, kernel_size, quantile):
rows, cols = img.shape
newmat = np.zeros((rows, cols))
kerny = int((kernel_size - 1) / 2)
for r in range(rows):
rmin = max(r - kerny, 0)
rmax = min(r + kerny + 1, rows)
for c in range(cols):
cmin = max(c - kerny, 0)
cmax = min(c + kerny + 1, cols)
miniimg = img[rmin:rmax, cmin:cmax]
newmat[r, c] = np.quantile(miniimg, quantile)
return newmat
quantile_blurred_img = apply_quantileblur(img, 5, 0.15)
plt.imshow(quantile_blurred_img)
plt.title('0.15 quantile blurred image')
plt.show()
quantile_blurred_img = apply_quantileblur(img, 5, 0.85)
plt.imshow(quantile_blurred_img)
plt.title('0.85 quantile blurred image')
plt.show()以下哪项输出:

由于medianBlur正在做一件非常类似的事情,大约快1000倍,我想知道如何改进这个过程,使其真正可用。
编辑:
到目前为止,我已经比较了4种不同的方法:
from scipy.ndimage import generic_filter
import time
import diplib
# sudo apt install default-jre
# sudo apt-get install freeglut3
import cv2
import numpy as np
from matplotlib import pyplot as plt
def show_img(img, title):
plt.imshow(img)
plt.title(title)
plt.show()
def apply_quantileblur_manual(img, kernel_size, quantile):
rows, cols = img.shape
newmat = np.zeros((rows, cols))
kerny = int((kernel_size - 1) / 2)
for r in range(rows):
rmin = max(r - kerny, 0)
rmax = min(r + kerny + 1, rows)
for c in range(cols):
cmin = max(c - kerny, 0)
cmax = min(c + kerny + 1, cols)
miniimg = img[rmin:rmax, cmin:cmax]
newmat[r, c] = np.quantile(miniimg, quantile)
return newmat
def apply_quantileblur_generic(img, kernel_size, quantile):
return generic_filter(img, lambda x: np.quantile(x, quantile), size=kernel_size)
def medianblur(img, kernel_size):
return cv2.medianBlur(img, kernel_size)
def diplib_blur(img, kernel_size, quantile):
k = diplib.Kernel([kernel_size,kernel_size])
z = diplib.PercentileFilter(img, quantile, k)
return z
img = np.random.randint(0,255,(500, 500), np.uint8)
cv2.imwrite('ugh.tiff', img)
dip_img = diplib.ImageReadTIFF('ugh.tiff')
kernel_size = 111
quantile = 50
start = time.time()
manual_img = apply_quantileblur_manual(img, kernel_size, quantile / 100)
print(time.time() - start)
start = time.time()
generic_img = apply_quantileblur_generic(img, kernel_size, quantile / 100)
print(time.time() - start)
start = time.time()
median_img = medianblur(img, kernel_size)
print(time.time() - start)
start = time.time()
diplib_img = diplib_blur(img, kernel_size, quantile)
print(time.time() - start)打印的内容:
31.994836568832397
46.67619204521179
0.005266904830932617
1.999727725982666所以OpenCV实际上快了10.000,但是没有指定分位数的选项。
发布于 2021-01-31 00:57:40
在scipy.ndimage库中有一个函数可以执行您所要求的操作:percentile_filter
from scipy.ndimage import percentile_filter
percentile_blur = percentile_filter(img, percentile=20, size=15)与generic_filter实现相比,您可以预期性能提升40倍。
发布于 2021-01-20 02:19:19
可以使用generic_filter()重写您的函数
from scipy.ndimage import generic_filter
def apply_quantileblur(img, kernel_size, quantile):
return generic_filter(img, lambda x: np.quantile(x, quantile), size=kernel_size)文档:https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.generic_filter.html
https://stackoverflow.com/questions/65796927
复制相似问题