【问题标题】:Sliding window on an image to calculate variance of pixels in that window在图像上滑动窗口以计算该窗口中像素的方差
【发布时间】:2021-08-04 18:22:10
【问题描述】:

我正在尝试构建一个函数,该函数使用滑动窗口和图像并计算窗口中像素的方差并返回观察到的最大方差的边界框。

我是编码新手,我尝试过 this post 的解决方案,但我不知道如何在其中输入图像而不是数组。

我在这里的最后期限,并且一直在尝试这个,所以非常感谢任何帮助。 TIA

编辑:另外,如果有人可以帮助我了解如何调用 rolling_window_lastaxis 函数并将其修改为我想要做的,那么这将意味着很多。

【问题讨论】:

  • 查看pyimagesearch中的教程
  • 是的,我也这样做了。它为我在不同位置生成多个输出窗口。

标签: python opencv image-processing jupyter-notebook


【解决方案1】:

这是使用 Python/OpenCV/Skimage 计算滑动窗口方差(或标准差)的一种方法。

此方法使用以下形式来计算方差(请参阅https://en.wikipedia.org/wiki/Variance):

Variance = mean of square of image - square of mean of image

但是,由于方差会在 8 位范围之外,我们取平方根来形成标准差。

我还使用了 Skimage 秩滤波器模块中的(局部)均值滤波器。

输入:

import cv2
import numpy as np
from skimage.morphology import rectangle
import skimage.filters as filters

# Variance = mean of square of image - square of mean of image
# See # see https://en.wikipedia.org/wiki/Variance

# read the image
# convert to 16-bits grayscale since mean filter below is limited 
# to single channel 8 or 16-bits, not float
# and variance will be larger than 8-bit range
img = cv2.imread('lena.png', cv2.IMREAD_GRAYSCALE).astype(np.uint16)

# compute square of image
img_sq = cv2.multiply(img, img)

# compute local mean in 5x5 rectangular region of each image
# note: python will give warning about slower performance when processing 16-bit images
region = rectangle(5,5)
mean_img = filters.rank.mean(img, selem=region)
mean_img_sq = filters.rank.mean(img_sq, selem=region)

# compute square of local mean of img
sq_mean_img = cv2.multiply(mean_img, mean_img)

# compute variance using float versions of images
var = cv2.add(mean_img_sq.astype(np.float32), -sq_mean_img.astype(np.float32))

# compute standard deviation and convert to 8-bit format
std = cv2.sqrt(var).clip(0,255).astype(np.uint8)

# save results
# multiply by 2 to make brighter as an example
cv2.imwrite('lena_std.png',2*std)

# show results
# multiply by 2 to make brighter as an example
cv2.imshow('std', 2*std)  
cv2.waitKey(0)
cv2.destroyAllWindows()

5x5 滑动窗口的局部标准偏差图像:

添加

这是一个版本,它找到边界框大小的最大平均方差的边界框,并将其绘制在方差图像上(实际上是标准偏差)。

import cv2
import numpy as np
from skimage.morphology import rectangle
import skimage.filters as filters

# Variance = mean of square of image - square of mean of image
# See # see https://en.wikipedia.org/wiki/Variance

# set the bounding box size
bbox_size = 25

# read the image
# convert to 16-bits grayscale since mean filter below is limited 
# to single channel 8 or 16-bits, not float
# and variance will be larger than 8-bit range
img = cv2.imread('lena.png', cv2.IMREAD_GRAYSCALE).astype(np.uint16)

# compute square of image
img_sq = cv2.multiply(img, img)

# compute local mean in bbox_size x bbox_size rectangular region of each image
# note: python will give warning about slower performance when processing 16-bit images
region = rectangle(bbox_size, bbox_size)
mean_img = filters.rank.mean(img, selem=region)
mean_img_sq = filters.rank.mean(img_sq, selem=region)

# compute square of local mean of img
sq_mean_img = cv2.multiply(mean_img, mean_img)

# compute variance using float versions of images
var = cv2.add(mean_img_sq.astype(np.float32), -sq_mean_img.astype(np.float32))

# compute standard deviation and convert to 8-bit format
std = cv2.sqrt(var).clip(0,255).astype(np.uint8)

# find bbox_size x bbox_size region with largest var (or std)
# get the moving window average at each pixel
std_ave = (cv2.sqrt(var)).astype(np.uint8)

# find the pixel x,y with the largest mean
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(std_ave)
x,y = max_loc
print("x:", x, "y:", y, "max:", max_val)

# draw rectangle for bounding box on copy of std image
result = std.copy()
result = cv2.merge([result, result, result])
cv2.rectangle(result, (x, y), (x+bbox_size, y+bbox_size), (0,0,255), 1)

# save results
# multiply by 2 to make brighter as an example
cv2.imwrite('lena_std.png',std)
cv2.imwrite('lena_std_bbox.png',result)

# show results
# multiply by 2 to make brighter as an example
cv2.imshow('std', std)  
cv2.imshow('result', result)  
cv2.waitKey(0)
cv2.destroyAllWindows()

x: 208 y: 67 max: 79.0

结果边界框:

【讨论】:

  • 这太好了,给了我一些想法,非常感谢。但我想在原始图像上放置一个边界框。边界框应该在像素之间变化最大的地方。
  • 你如何衡量它?您想要具有最亮区域的单个像素吗?你知道你想要多大的边界框。如果您考虑到大小,一次可以获得滑动边界框内所有像素的最亮平均值。
  • 基本上执行对象检测,但通过基于规则的方法。这里的规则是绘制一个像素变化的边界框。大小应取决于图像的大小和像素变化的区域。这是否有助于您更好地理解?
  • 否,您必须为边界框指定唯一的大小或定义确定边界框大小的特定数学规则。不同大小的边界框将识别不同大小的区域。您必须测试每个大小的边界框以找到具有最小平均方差(或标准偏差)的边界框。用于产生方差的窗口大小也很重要。
  • 这就是我的意思,定义一个确定边界框大小的数学规则。我该如何完成整个任务?你能帮忙吗?
【解决方案2】:

计算WxH 区域中的窗口/滚动方差的另一种方法是仅将numpyscipy 与卷积一起使用,它们的计算速度相当快。一个例子:

import numpy as np
import scipy.signal
# Create image data
original = np.zeros((811,123))
img = original + np.random.normal(0, 1, original.shape)
# Create averaging kernel
H, W = 5, 5
mean_op = np.ones((H,W))/(H*W)
# Carry out convolution to compute mean of square, and square of mean
mean_of_sq = scipy.signal.convolve2d( img**2, mean_op, mode='same', boundary='symm')
sq_of_mean = scipy.signal.convolve2d( img   , mean_op, mode='same', boundary='symm') **2
win_var    = mean_of_sq - sq_of_mean

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    相关资源
    最近更新 更多