0

I am trying to do simple prewitt edge detection on an image and output 2 images with horizontal and vertical edges. For some reason, whenever the output value should be negative (for example -3), my output array ends up with 256 minus that value (253) giving me a huge amount of background. I tried adding these if/elif/else statements but that helped not at all. I am using the code below and clueless as to what's going wrong:

for i in range(1,(len(os.listdir(images)))):
    image=plt.imread(images+(os.listdir(images)[i]))
    if len(image.shape)>2:
        img=image[:,:,0]
    else:
        img=image

    imgC=deepcopy(img)
    imgD=deepcopy(img)
    imgE=deepcopy(img) 

    for x in range(1,img.shape[1]-2):
        for y in range(1,img.shape[0]-2):
            avgA=(img[(y-1),x]+img[(y-1),(x+1)]+img[(y-1),(x-1)])
            avgC=(img[(y+1),x]+img[(y+1),(x+1)]+img[(y+1),(x-1)])
            avgT=(img[(y-1),(x-1)]+img[y,(x-1)]+img[(y+1),(x-1)])
            avgB=(img[(y-1),(x+1)]+img[y,(x+1)]+img[(y+1),(x+1)])

            if (avgA-avgC)<0:
                imgC[y,x]=0
            elif (avgA-avgC)>255:
                imgC[y,x]=255
            else:
                imgC[y,x]=(avgA-avgC)
            if (avgT-avgB)<0:
                imgD[y,x]=0
            elif (avgT-avgB)>255:
                imgD[y,x]=255
            else:
                imgD[y,x]=(avgT-avgB)
            imgE[y,x]=math.sqrt(((imgC[y,x]**2)+(imgD[y,x]**2)))
Jan Spurny
  • 5,219
  • 1
  • 33
  • 47
user3470496
  • 141
  • 7
  • 33
  • 1
    I don't know the solution to your problem but I think that if you do not divide your avgA, avgC, avgT, avgB by 3 (the number of elements you use to calculate the averages), you might end up with a lot more 255 than you expect – Julien Spronck Mar 25 '15 at 16:53

1 Answers1

0

Values in that image are stored as unsigned bytes (0..255 range), so this is probably the problem as subtracting two unsigned bytes would lead to overflow and you would get that 253 instead of -3.

You need to convert those values into an int. Something like this could work:

...
avgA = int(img[(y-1),x]) + int(img[(y-1),(x+1)]) + int(img[(y-1),(x-1)])
avgC = int(img[(y+1),x]) + int(img[(y+1),(x+1)]) + int(img[(y+1),(x-1)])
avgT = int(img[(y-1),(x-1)]) + int(img[y,(x-1)]) + int(img[(y+1),(x-1)])
avgB = int(img[(y-1),(x+1)]) + int(img[y,(x+1)]) + int(img[(y+1),(x+1)])

imgC[y, x] = avgA - avgC
imgD[y, x] = avgT - avgB
...

But I'm pretty sure you would get better (faster, less error prone code) results using generic convolution function, like PIL.Image.filter(''<filter>'') with filter matrix created using PIL.ImageFilter.Kernel(..) for PIL library - http://pillow.readthedocs.org/en/latest/reference/ImageFilter.html Or convolve of numpy/scipy libraries, as shown here: http://juanreyero.com/article/python/python-convolution.html

Edit: as Julien Spronck pointed out - your resulting value in imgE is completely out of range and you should generally divide it by a number of pixels (i.e. sum of all values in the convolution matrix) used in calculation of that result.

Jan Spurny
  • 5,219
  • 1
  • 33
  • 47