2011-04-03 83 views
5

编辑:感谢霍华德,我在这里纠正代码,它似乎是现在的工作。这个python图像模糊函数有什么问题?

EDIT2:我已经更新了代码以包含垂直模糊。使用不同的设置产生的样本输出:Blur comparison images.jpg

的模糊操作的另一个参考(JAVA):Blurring for Beginners


原帖:

我想了解基本的图像处理和重复这个简单Blur method在python(在“重用结果”第二功能BlurHorizo​​ntal)。我知道PIL中已经有模糊函数,但我想自己尝试基本的像素操作。

该函数应该获取源图像,然后基于某个半径平均RGB像素值并将处理后的图像写入新文件。我的问题是,我得到了很多的像素与完全错误的平均值(例如,亮绿色的线,而不是红色在某些领域)。

模糊半径为2时,平均方法将以输入像素为中心的5个像素的RGB值相加。它使用“滑动窗口”,以保持一个运行总计,减去传出像素(左侧)以及将所述新的输入像素(窗口的右侧)。 Blur method explained here

样品:Blur test image output.jpg

在那里我已经出了错任何想法?我不知道为什么图像的某些部分干净模糊而其他地区都充满了色彩完全无关的周边地区。

感谢您的帮助。

固定的工作守则(感谢霍华德)

import Image, numpy, ImageFilter 
img = Image.open('testimage.jpg') 

imgArr = numpy.asarray(img) # readonly 

# blur radius in pixels 
radius = 2 

# blur window length in pixels 
windowLen = radius*2+1 

# columns (x) image width in pixels 
imgWidth = imgArr.shape[1] 

# rows (y) image height in pixels 
imgHeight = imgArr.shape[0] 

#simple box/window blur 
def doblur(imgArr): 
    # create array for processed image based on input image dimensions 
    imgB = numpy.zeros((imgHeight,imgWidth,3),numpy.uint8) 
    imgC = numpy.zeros((imgHeight,imgWidth,3),numpy.uint8) 

    # blur horizontal row by row 
    for ro in range(imgHeight): 
     # RGB color values 
     totalR = 0 
     totalG = 0 
     totalB = 0 

     # calculate blurred value of first pixel in each row 
     for rads in range(-radius, radius+1): 
      if (rads) >= 0 and (rads) <= imgWidth-1: 
       totalR += imgArr[ro,rads][0]/windowLen 
       totalG += imgArr[ro,rads][1]/windowLen 
       totalB += imgArr[ro,rads][2]/windowLen 

     imgB[ro,0] = [totalR,totalG,totalB] 

     # calculate blurred value of the rest of the row based on 
     # unweighted average of surrounding pixels within blur radius 
     # using sliding window totals (add incoming, subtract outgoing pixels) 
     for co in range(1,imgWidth): 
      if (co-radius-1) >= 0: 
       totalR -= imgArr[ro,co-radius-1][0]/windowLen 
       totalG -= imgArr[ro,co-radius-1][1]/windowLen 
       totalB -= imgArr[ro,co-radius-1][2]/windowLen 
      if (co+radius) <= imgWidth-1: 
       totalR += imgArr[ro,co+radius][0]/windowLen 
       totalG += imgArr[ro,co+radius][1]/windowLen 
       totalB += imgArr[ro,co+radius][2]/windowLen 

      # put average color value into imgB pixel 

      imgB[ro,co] = [totalR,totalG,totalB] 

    # blur vertical 

    for co in range(imgWidth): 
     totalR = 0 
     totalG = 0 
     totalB = 0 

     for rads in range(-radius, radius+1): 
      if (rads) >= 0 and (rads) <= imgHeight-1: 
       totalR += imgB[rads,co][0]/windowLen 
       totalG += imgB[rads,co][1]/windowLen 
       totalB += imgB[rads,co][2]/windowLen 

     imgC[0,co] = [totalR,totalG,totalB] 

     for ro in range(1,imgHeight): 
      if (ro-radius-1) >= 0: 
       totalR -= imgB[ro-radius-1,co][0]/windowLen 
       totalG -= imgB[ro-radius-1,co][1]/windowLen 
       totalB -= imgB[ro-radius-1,co][2]/windowLen 
      if (ro+radius) <= imgHeight-1: 
       totalR += imgB[ro+radius,co][0]/windowLen 
       totalG += imgB[ro+radius,co][1]/windowLen 
       totalB += imgB[ro+radius,co][2]/windowLen 

      imgC[ro,co] = [totalR,totalG,totalB] 

    return imgC 

# number of times to run blur operation 
blurPasses = 3 

# temporary image array for multiple passes 
imgTmp = imgArr 

for k in range(blurPasses): 
    imgTmp = doblur(imgTmp) 
    print "pass #",k,"done." 

imgOut = Image.fromarray(numpy.uint8(imgTmp)) 

imgOut.save('testimage-processed.png', 'PNG') 
+2

你可以张贴一些样品输入/输出? – Blender 2011-04-03 05:46:21

+1

当我看到'a-b-c'时,我总是很担心。我从来没有记得任何语言的运算符的关联性,以便知道它是否会被解释为'a-(bc)'或'(ab)-c' – sarnold 2011-04-03 06:05:33

+1

在我使用的每种语言中,加法,减法,乘法,和师从左到右,如数学。幂指数是唯一经常将右向左联系起来的常见现象。 – 2011-04-03 06:08:49

回答

2

我想你有一个问题与运行到只有半径1(范围排除最后)行

for rads in range(-radius, radius): 

。添加一个到第二个范围参数。

更新:有行

if (co-radius-1) > 0: 

内的另一个小isue这应该是

if (co-radius-1) >= 0: 
+0

感谢您的所有意见。我尝试了霍华德的建议,并改为以下行: '对于拉德在范围内(-radius,半径+ 1)': 但我仍然必须有另一个问题的地方。 下面是一个示例图像,显示图像之前和之后。第二张图片由我的原始代码处理。霍华德改变后,第三张图像被处理。 [模糊测试图像输出.jpg](http://i.imgur.com/U16Bf.jpg) – moski 2011-04-03 12:19:39

+0

@moski还有一个小问题:if(co-radius-1)> 0:should if if(co -radius-1)> = 0. – Howard 2011-04-03 12:32:45

+0

非常感谢!我认为这两项修改已经解决了我的错误。我倾向于错过所有的小东西,>对>> =和+1,-1来计算从0开始计数。1.感谢第二组眼睛。我会尝试一些不同的图像,而不是发布更新。 [Blur FIXED output.png](http://i.imgur.com/2ECNM.png) – moski 2011-04-03 12:39:03

0

我修改/重构你的代码只是有点,我想我会分享。我需要的东西做一个自定义的模糊,将:1)数据阵列上工作,和2)只有水平和垂直不换。正如TODO所指出的那样,我正在考虑进一步重构,以便它可以进行部分像素混合(即0.5)。希望这可以帮助别人:

def blur_image(image_data, blur_horizontal=True, blur_vertical=True, height=256, width=256, radius=1): 
    #TODO: Modify to support partial pixel blending 

    # blur window length in pixels 
    blur_window = radius*2+1 

    out_image_data = image_data 

    # blur horizontal row by row, and wrap around edges 
    if blur_horizontal: 
     for row in range(height): 
      for column in range(0, width): 
       total_red = 0 
       total_green = 0 
       total_blue = 0 

       for rads in range(-radius, radius+1): 
        pixel = (row*width) + ((column+rads) % width) 
        total_red += image_data[pixel][0]/blur_window 
        total_green += image_data[pixel][1]/blur_window 
        total_blue += image_data[pixel][2]/blur_window 

       out_image_data[row*width + column] = (total_red, total_green, total_blue, 255) 
     image_data = out_image_data 

    # blur vertical, but no wrapping 
    if blur_vertical: 
     for column in range(width): 
      for row in range(0, height): 
       total_red = 0 
       total_green = 0 
       total_blue = 0 

       blur_window = 0 
       for rads in range(-radius, radius+1): 
        if rads in range(0, height): 
         blur_window += 1 

       for rads in range(-radius, radius+1): 
        row_mod = row+rads 
        if row_mod in range(0, height): 
         pixel = (row_mod*width) + column 
         total_red += image_data[pixel][0]/blur_window 
         total_green += image_data[pixel][1]/blur_window 
         total_blue += image_data[pixel][2]/blur_window 

       out_image_data[row*width + column] = (total_red, total_green, total_blue, 255) 
     image_data = out_image_data 

    return image_data 

你可以使用它时,你已经得到了在RGBA像素阵列的图像,然后运行:

image_data = blur_image(image_data, height=height, width=width, radius=2) 

im = Image.new('RGB', (width, height)) 
im.putdata(image_data)