使用 STD 对图像进行平滑处理

Smoothing Process Over an Image Using STD

import cv2

将 numpy 导入为 np 导入 scipy 导入 matplotlib.pyplot 作为情节 从 PIL 导入图像 从 skimage 导入 io 导入 glob 从 skimage 导入 io,img_as_float

img = cv2.imread(r"C:\Users\hoday\Desktop\GRAPE_IMG\GrapeBox.jpg", 1) img = np.float32(img)

blue_img, green_img, red_img = cv2.split(img) #将图像分成3个通道 - BGR

频道 = [blue_img、green_img、red_img] std_channels = []

频道中的频道:

lst = []           

img_row = (channel.shape)[0]
img_col = (channel.shape)[1]

for row in range(1, img_row-1): #for 5X5 1--->2
    for col in range(1, img_col-1): #for 5X5 1--->2
        mask = channel[row-1:row+2, col-1:col+2] #for 5X5 ---> mask = channel[row-2:row+3, col-2:col+3]
        lst.append(mask.std())
        
std_channel = np.array(lst)        
std_channel = std_channel.reshape(img_row-2, img_col-2) #for 5X5 2--->4
std_channels.append(std_channel)

img_merged = cv2.merge(std_channels) cv2.imwrite(r"C:\Users\hoday\Desktop\GRAPE_IMG\normalStd.png", img_merged)

你好, 我正在尝试遍历图像的像素并取出由 std 组成的新图像 就像下一个视频中所做的那样:

https://www.youtube.com/watch?v=ZoaEDbivmOE&t=80s

我将图像分成 3 个通道,并尝试为每个通道更新一个新数组,但是当我尝试 运行 代码时,我卡住了。例如,不是像预期的那样为 img[0:3, 0:3].std() 打印值 5.58,它打印的值是 1.28 - 现在这是 std 的值一个频道,但我想要一个与所有三个频道合并...

可能我没有以正确的方式合并频道,但我不知道我还能怎么做。

更新答案

您可以使用 Numba 将其降低到 1 毫秒以下:

#!/usr/bin/env python3

import cv2
import numba as nb
import numpy as np
import math

@nb.jit(nopython=True, parallel=True, fastmath=True)
def numbaStd(im):
    # Allocate space for result
    res = np.zeros_like(im)
    h, w, c = im.shape
    for row in nb.prange(1,h-1):
        for col in range(1,w-1):
            for band in range(c):
                x0 = im[row-1,col-1,band]
                x1 = im[row-1,col  ,band]
                x2 = im[row-1,col+1,band]
                x3 = im[row  ,col-1,band]
                x4 = im[row  ,col  ,band]
                x5 = im[row  ,col+1,band]
                x6 = im[row+1,col-1,band]
                x7 = im[row+1,col  ,band]
                x8 = im[row+1,col+1,band]
                mu = (x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8) / 9
                S  = (x0 - mu)**2
                S += (x1 - mu)**2
                S += (x2 - mu)**2
                S += (x3 - mu)**2
                S += (x4 - mu)**2
                S += (x5 - mu)**2
                S += (x6 - mu)**2
                S += (x7 - mu)**2
                S += (x8 - mu)**2
                res[row,col,band] = math.sqrt(S/9)
    return res

# Open image and make into Numpy array
im  = cv2.imread('grapes.jpg', cv2.IMREAD_COLOR)

# Call Numba standard deviation
res = numbaStd(im)

# Optional block to contrast stretch result image
res[...,0] = 255.0*res[...,0]/res[...,0].max()
res[...,1] = 255.0*res[...,1]/res[...,1].max()
res[...,2] = 255.0*res[...,2]/res[...,2].max()

# Save result
cv2.imwrite("result.png", res)

# IPython timing
#%timeit numbaStd(im)


In [19]: %timeit numbaStd(im)
864 µs ± 20.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


原答案

您可以更简单地使用 SciPy generic_filter 在图像上传递 3x3 window,如下所示:

#!/usr/bin/env python3

import numpy as np
from PIL import Image
from scipy.ndimage import generic_filter

# Stddev filter
def stddev(P):
    """
    We receive P[0]..P[8] with the pixels in the 3x3 surrounding window.
    """
    return np.std(P)

# Open image and make into Numpy array
im = Image.open('paddington.png')
im = np.array(im)

# Run 3x3 stddev filter on one band/channel at a time
im[...,0] = generic_filter(im[...,0], stddev, (3, 3))
im[...,1] = generic_filter(im[...,1], stddev, (3, 3))
im[...,2] = generic_filter(im[...,2], stddev, (3, 3))

# Save result
Image.fromarray(im).save('result.png')

变成这样:

进入这个:


顺便说一下,您可以在终端中使用 ImageMagick 做同样的事情,而无需编写任何代码,如下所示:

magick paddington.png -separate -statistic standarddeviation 3x3 -combine result.png