首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用3x3内核平滑图像

如何用3x3内核平滑图像
EN

Stack Overflow用户
提问于 2018-06-07 17:29:50
回答 2查看 3.2K关注 0票数 3

我试图平滑一个图像,通过循环遍历它的像素,计算一个3x3补丁的平均值,然后将平均值应用到这个补丁中的所有9个像素。

代码:

代码语言:javascript
复制
    import matplotlib.pyplot as plt
    import numpy as np
    import cv2 as cv
    from PIL import Image


    # 1. Load Image
    name = 'ebay.png'
    img = cv.imread(name) #import image

    h, w = img.shape[:2]


    # 2. Smooth with kernel size 3

    for y in range(0, w, 3):
        for x in range(0, h, 3):     
            px1 = img[x][y] #0/0
            px2 = img[x][y+1] #0/1
            px3 = img[x][y+2] #0/2
            px4 = img[x+1][y] #1/0
            px5 = img[x+1][y+1] #1/1
            px6 = img[x+1][y+2] #1/2
            px7 = img[x+2][y] #2/0
            px8 = img[x+2][y+1] #2/1
            px9 = img[x+2][y+2] #2/2

            average = np.average(px1 + px2 + px3 + px4 + px5 + px6 + px7 + px8 + px9)    

            img[x][y] =  average  #0/0
            img[x][y+1] = average   #0/1
            img[x][y+2] = average   #0/2
            img[x+1][y] = average   #1/0
            img[x+1][y+1] = average   #1/1
            img[x+1][y+2] = average  #1/2
            img[x+2][y] = average  #2/0
            img[x+2][y+1] = average   #2/1
            img[x+2][y+2] = average  #2/2

# 3. Transform the resulting image into pgm format and save result        

new_image = Image.fromarray(img)
new_image.save('new.png')

# 4. Show image

new_image.show()

However this just makes my new image just very pixely and not smooth at all. 

我假设我在这里做错了什么:

代码语言:javascript
复制
average = np.average(px1 + px2 + px3 + px4 + px5 + px6 + px7 + px8 + px9)

因为,当我只使用px5作为平均值时,新的图像看起来要好得多(但仍然不是很流畅)。请参阅下图:

原始图像:

我的代码现在所做的是:

结果当我使用px5作为平均值时:

结果当添加所有px并除以9:

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-07 20:23:03

因此,我在这里有两个问题,我能够弄清楚,这要感谢@Ernie Yang和@Cris Luengo。非常感谢您的帮助!

1)我的平均计算的问题是,它是溢出的,我是在总结像素值。这就是为什么结果看起来很奇怪,因为它被包围了。所以我不得不改变:

代码语言:javascript
复制
average = np.average(px1 + px2 + px3 + px4 + px5 + px6 + px7 + px8 + px9)

至:

代码语言:javascript
复制
average = px1/9. + px2/9. + px3/9. + px4/9. + px5/9. + px6/9. + px7/9. + px8/9. + px9/9.

2)然而,这并没有使我的图像平滑,因为我只是将平均值分配给补丁中的所有9个像素。因此,这导致图片被像素化,而不是平滑。因此,我不得不将平均值的结果只写到中间像素,而不是写到邻里所有的3x3像素。我还必须把它写到一个单独的输出映像中。您无法在适当位置执行此操作,因为它将影响后续像素的结果。

正确的代码示例:

代码语言:javascript
复制
    import matplotlib.pyplot as plt
    import numpy as np
    import cv2 as cv
    from PIL import Image
    import scipy.ndimage as ndimage
    from scipy.ndimage.filters import gaussian_filter


    # 1. Load Image
    name = 'ebay.png'
    img = cv.imread(name) #import image


    h, w = img.shape[:2]
    smoothedImage = cv.imread(name) #initialize second image


    # 2. Smooth with with kernel size 3

    for y in range(0, w-2):
        for x in range(0, h-2):     
            px1 = img[x][y] #0/0
            px2 = img[x][y+1] #0/1
            px3 = img[x][y+2] #0/2
            px4 = img[x+1][y] #1/0
            px5 = img[x+1][y+1] #1/1
            px6 = img[x+1][y+2] #1/2
            px7 = img[x+2][y] #2/0
            px8 = img[x+2][y+1] #2/1
            px9 = img[x+2][y+2] #2/2

            average = px1/9. + px2/9. + px3/9. + px4/9. + px5/9. + px6/9. + px7/9. + px8/9. + px9/9.

            smoothedImage[x+1][y+1] = average   #1/1

    # 3. Transform the resulting image into pgm format and save result        

    new_image = Image.fromarray(smoothedImage)
    new_image.save('new.png')

    # 4. Show image

    new_image.show()

原始图像:

平滑图像:

编辑:

嘿,伙计们,我下午午睡回来了。我有很多有趣的想法,下面是我改进的代码:

代码语言:javascript
复制
import matplotlib.pyplot as plt
import numpy as np
import cv2 as cv
from PIL import Image
import scipy.ndimage as ndimage
from scipy.ndimage.filters import gaussian_filter


# 1. Load Image
name = 'ebay.png'
img = cv.imread(name) #import image
h, w = img.shape[:2]
kernel = 5
radius = (kernel-1)/2

img2 = np.zeros((h, w, 3), dtype = 'uint8') #new image to paint on

    def pxIsInImgRange(x, y):
        if (0<=x) and (x < w): 
                if (0<=y) and (y < h):
                    return True
        return False

    # 2. Smoothing the shit out

    for x in range (-radius, w+radius):
        for y in range (-radius, h+radius):

            if pxIsInImgRange(x,y): 

                    px = 0

                    for vx2 in range (-radius, radius+1):
                        for vy2 in range (-radius, radius+1):
                            x2 = x + vx2
                            y2 = y + vy2
                            if pxIsInImgRange(x2,y2):

                                px = px + (img[y2][x2]/float((kernel*kernel)))
                            else:
                                px = px + 0 


                    img2[y][x] = px

    # 3. Save image                

    new_image = Image.fromarray(img2)
    new_image.save('new.png')

    # 4. Show image

    new_image.show()

内核为5的新结果:

票数 4
EN

Stack Overflow用户

发布于 2018-06-07 17:36:36

代码语言:javascript
复制
average = np.average(px1 + px2 + px3 + px4 + px5 + px6 + px7 + px8 + px9)

是对数值的实际求和,而不是平均值,

代码语言:javascript
复制
average = (px1 + px2 + px3 + px4 + px5 + px6 + px7 + px8 + px9)/9

应该给你你想要的。

对于这样的任务,scipy.signal.convolve2d也是最好的工具。参见下面的文档和示例。

https://www.google.com/search?q=scipy.signal.convolve2d&oq=scipy.signal.convolve2d&aqs=chrome..69i57j69i60&sourceid=chrome&ie=UTF-8

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50747064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档