计算numpy/scipy中的开窗概率 [英] calculating windowed probabilities in numpy/scipy

查看:83
本文介绍了计算numpy/scipy中的开窗概率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用numpy/scipy在图像上做一些(我认为)模糊的过滤器.我想要的本质上是窗口概率分布.我从灰度图像开始.对于给定的像素和NxN内核,且N为奇数,我想相对于内核中的其他像素计算该像素值的概率.此外,我想尽快进行此计算.

I'm trying to do a bit of (I think) an obscure filter on an image using numpy/scipy. What I want is essentially a windowed probability distribution. I start with a grayscale image. For a given pixel and an NxN kernel, with N odd, I want to calculate that pixel value's probability, relative to the other pixels in the kernel. Furthermore, I want to do this calculation as fast as possible.

例如,给定图像的3x3区域:

So for example given a 3x3 region of an image:

[0, 0, 0;
 0, 0, 0;
 255, 255, 255]

应该将中心像素从0转换为0.66,因为它在该3x3区域中有2/3的几率发生.在代码中,我可以执行以下操作,但是速度太慢:

The center pixel should be converted from 0 to 0.66 since it has a 2/3 chance of occurring in that 3x3 region. In code, I can do as follows, but it's way too slow:

# loops through calculating probability distributions for each window
# generates new_image
for yi in range(0, height):
  for xi in range(0, width):
    window = kernel_region(image, yi, xi, ksize)
    hist = np.histogram(window.ravel(), 256, [0, 256])
    pdf = hist / np.size(window)
    pixel_value = image[yi, xi]
    new_image[yi, xi] = pdf[pixel_value]

# gives ksize x ksize slice of the image (smaller on the edges)
def kernel_region(image, yi, xi, ksize):
  height, width = image.shape[:2]
  offset = math.floor(ksize / 2)
  yStart = max(0, yi - offset)
  yEnd = min(height - 1, yi + offset)
  xStart = max(0, xi - offset)
  xEnd = min(width - 1, xi + offset)
  return image[yStart:yEnd, xStart:xEnd]

我可以在循环中进行一些优化,但我想完全避免使用循环.可以使用纯" numpy函数吗?

There are some optimizations I could make in the loop but I'd like to avoid using a loop at all. Is this possible using "pure" numpy functions?

推荐答案

有趣的数学问题,似乎可以通过

Interesting math problem and seems like there would be a simple solution with Scikit-image's view_as_windows to get (3,3) sliding windows and then comparing against the center pixel for getting the count of its occurrence in its window and finally dividing by the kernel size of 9.

因此,图像a的实现应为-

Hence, the implementation for an image a would be -

from skimage.util.shape import view_as_windows

(view_as_windows(a,(3,3)) == a[1:-1,1:-1,None,None]).sum((-2,-1))/9.0

这使我们获得了非边界元素的结果.为了覆盖所有元素,我们可以使用无效的说明符填充图像,例如在图像周围加上-1,然后使用建议的方法.

This gets us the results for the non-boundary elements. To cover for all the elements, we can pad the image with an invalid specifier, say -1 around it and then use the proposed method.

样品运行-

In [61]: a
Out[61]: 
array([[  1,   0,   0,   0,   3,   4],
       [  2,   0,   0,   0,   6,   0],
       [  4, 255, 255, 255,   8,   2],
       [  0,   5,   0,   5,   6,   2]])

In [76]: (view_as_windows(a,(3,3)) == a[1:-1,1:-1,None,None]).sum((-2,-1))/9.0
Out[76]: 
array([[ 0.44,  0.67,  0.44,  0.11],
       [ 0.22,  0.33,  0.22,  0.11]])

涵盖所有元素-

In [74]: a1 = np.pad(a, (1,1), 'constant', constant_values=(-1, -1))

In [75]: (view_as_windows(a1,(3,3)) == a1[1:-1,1:-1,None,None]).sum((-2,-1))/9.0
Out[75]: 
array([[ 0.11,  0.44,  0.67,  0.44,  0.11,  0.11],
       [ 0.11,  0.44,  0.67,  0.44,  0.11,  0.11],
       [ 0.11,  0.22,  0.33,  0.22,  0.11,  0.22],
       [ 0.11,  0.11,  0.11,  0.11,  0.11,  0.22]])

这篇关于计算numpy/scipy中的开窗概率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆