2011-04-03 25 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)