Question

The intention of this program is to take a ppm image and emboss it. (The entire project details can be found here) I am helping with the grading of the assignment and cannot seem to find the student's bug.

The original image I am using looks like this: enter image description here

the results should look like this:

enter image description here

Here is the entirety of the program (with comments around the problem lines):

# making an image embossed 

import numpy 
def clamp(color):
    if color<0:
        return 0
    elif color>255:
        return 255
    else:
        return color
def get_num(jen):
    variable = ''
    ch = gwen.read(1)
    while ch.startswith('#'):
        while ch!='\n':

            ch=gwen.read(1)
        while ch.isspace():
            ch = gwen.read(1)
    while ch.isspace():
        ch = gwen.read(1)
    while ch.isdigit():

        variable = variable + ch
        ch=gwen.read(1)
    if ch.startswith('#'):
        while ch!='\n':

            ch=gwen.read(1)

    return int(variable)

def emboss(x,y):
    d=numpy.empty((h,w*3),numpy.uint8)
    print "len x[0]=",len(x[0])
    print "len y=", len(y)
    print "len y[0]=", len(y[0])
    for i in xrange(len(x)):
        for j in xrange(0,len(x[0]),3):
            for k in xrange(3): #r,g,b loop
                #if the next line is used a correct (but not embosed) image results
                #d[i][j+k] = x[i][j+k]
                sum = 0
                for l in xrange(0,3,1):
                    for m in xrange(0,3,1):
                        #the next line embosses but causes a triple image in the process
                        sum = sum + ((x[(i+(l-1))%h][((j+k)+((m-1)*3))%w]) * y[l][m])

                #the line below adjusts an embossed images brightness
                #if not embossing comment out this line
                d[i][j+k]=clamp(sum+127)


    return d


name=raw_input('Please enter input name: ')
output= raw_input('Please enter output name: ')
gwen=open(name,"rb")

ch=gwen.read(1)
if ch=='P':
    print ('This is P')
else:
    print('Error in Header')
ch=gwen.read(1)
if ch=='6':
    print ('This is 6')
else:
    print('Error in Header')
jen=''

w=get_num(jen)
w=int(w)
print w 
h=get_num(jen)
h=int(h)
print h
value=get_num(jen)
value=int(value)
print value

joe=open(output,"wb")
joe.write('P6'+' '+str(w)+' '+str(h)+' '+str(value)+'\n')



a=numpy.fromfile(gwen,numpy.uint8, w*h*3,'')
c=numpy.reshape(a,(h,w*3))
d=numpy.array([[1,1,1],[0,0,0],[-1,-1,-1]])
new=emboss(c,d)

for i in xrange(h):
    for j in xrange(0,w*3,3):
        r_value = new[i][j]
        r=int(clamp(r_value))
        g_value = new[i][j+1]
        g=int(clamp(g_value)) 
        b_value = new[i][j+2]
        b=int(clamp(b_value))
        joe.write('%c%c%c'%(r,g,b))

gwen.close()
joe.close()

The problem appears to me to be in the emboss method but I can't seem to fix it. So I included all of it even the part that filters out ppm header comments.

As it is now, it embosses but does a triple image in doing so. The triple image goes away when the embossing lines are removed.

here is the file I am testing with if you want to try it yourself

Any suggestions of what I should change to fix the bug?

Was it helpful?

Solution

Here's a cleaner version of the emboss function

# renamed
# x -> im (the input image numpy array)
# y -> kernel (the emboss kernel)
# i -> y (the y coordinate)
# j -> x (the x coordinate)
# d -> output (the output numpy array)
# k -> color (the number of the color channel 0-2)
# sum -> sum_ (sum is a built-in, so we shouldn't use that name)
def emboss(im,kernel):
    output=numpy.empty((h,w*3),numpy.uint8)
    print "len im[0]=",len(im[0])
    print "len kernel=", len(kernel)
    print "len kernel[0]=", len(kernel[0])
    for y in xrange(len(im)):
        for x in xrange(0,len(im[0]),3):
            for color in xrange(3): #r,g,b loop
                #if the next line is used a correct (but not embosed) image results
                #output[y][x+color] = im[y][x+color]
                sum_ = 0
                for l in xrange(0,3,1):
                    for m in xrange(0,3,1):
                        #the next line embosses but causes a triple image in the process
                        sum_ += (im[(y+(l-1))%h][((x+color)+((m-1)*3))%w]) * kernel[l][m]

                #the line below adjusts an embossed images brightness
                #if not embossing comment out this line
                output[y][x+color]=clamp(sum_+127)
    return output

The bug seems to be on this line

sum_ += (im[(y+(l-1))%h][((x+color)+((m-1)*3))%w]) * kernel[l][m]

Where the x-coord is moded by w (the image width in pixels). The x-coord varies from 0-1920 (due to the 3 channel colours) whereas the image width is only 640px. moding by (w*3) should correct the problem.

Here is the fix for the original code:

sum = sum + ((x[(i+(l-1))%h][((j+k)+((m-1)*3))%(w*3)]) * y[l][m])

OTHER TIPS

The code need many improvements, but for the bug:

sum = sum + ((x[(i+(l-1))%h][((j+k)+((m-1)*3))%(w*3)]) * y[l][m]) # %(w*3)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top