Python embossing with PIL - adding depth, bearing, etc.

I am trying to crop an image using PIL .

PIL provides a basic way to ImageFilter.EMBOSS image (using ImageFilter.EMBOSS ).

In image editing packages such as GIMP, you can change parameters such as azimuth, depth, and height in this embossed image.

How to do this with PIL? At least I want to adjust the depth of the relief image.

Update: I tried the suggestions Paul proposed (changing filterargs , for example scale, offset and matrices), but I could not change the effect of "depth". So keep looking for an answer.

Here is a comparison of the embossing effect using PIL (left) and GIMP (right). The original image is here, http://www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node74.html .

alt text

+6
python image-processing python-imaging-library
source share
2 answers

If you cannot achieve your goal using either a combination of operations (for example, spinning and then applying the EMBOSS filter, re-spinning) (or enhancing contrast and then embossing), you can resort to change (or creating your own).

In ImageFilter.py you will find this class:

 ## # Embossing filter. class EMBOSS(BuiltinFilter): name = "Emboss" filterargs = (3, 3), 1, 128, ( -1, 0, 0, 0, 1, 0, 0, 0, 0 ) 

Placing the -1 symbol in another corner of the matrix will change the azimuth and make it -2, it may have the effect you're looking for.

The matrix is ​​applied pixel-by-pixel. Each element in the matrix corresponds to the current pixel and surrounding pixels; a central value representing the current pixel. A new, transformed current pixel will be created as a combination of all 9 pixels weighted by the values ​​in the matrix. For example, a matrix with all zeros and 1 in the center will not change the image.

Additional parameters: scale and offset . For the built-in EMBOSS, the values ​​are 1 (scale) and 128 (offset). Changing these parameters will change the overall strength of the result.

From ImageFilter.py:

 # @keyparam scale Scale factor. If given, the result for each # pixel is divided by this value. The default is the sum # of the kernel weights. # @keyparam offset Offset. If given, this value is added to the # result, after it has been divided by the scale factor. 

Since I am not familiar with the effects of the GIMP Depth parameter, I cannot say that it is likely to do what you want.

You can also make a matrix of different sizes. Replace (3.3) with (5.5), and then create a 25-element matrix.

To make temporary changes to the filter without saving the source code again, simply do the following:

 ImageFilter.EMBOSS.filterargs=((3, 3), 1, 128, (-1, 0, 0, 0, 1, 0, 0, 0, 0)) 

Edit: (taking NumPy )

 from PIL import Image import numpy # defining azimuth, elevation, and depth ele = numpy.pi/2.2 # radians azi = numpy.pi/4. # radians dep = 10. # (0-100) # get a B&W version of the image img = Image.open('daisy.jpg').convert('L') # get an array a = numpy.asarray(img).astype('float') # find the gradient grad = numpy.gradient(a) # (it is two arrays: grad_x and grad_y) grad_x, grad_y = grad # getting the unit incident ray gd = numpy.cos(ele) # length of projection of ray on ground plane dx = gd*numpy.cos(azi) dy = gd*numpy.sin(azi) dz = numpy.sin(ele) # adjusting the gradient by the "depth" factor # (I think this is how GIMP defines it) grad_x = grad_x*dep/100. grad_y = grad_y*dep/100. # finding the unit normal vectors for the image leng = numpy.sqrt(grad_x**2 + grad_y**2 + 1.) uni_x = grad_x/leng uni_y = grad_y/leng uni_z = 1./leng # take the dot product a2 = 255*(dx*uni_x + dy*uni_y + dz*uni_z) # avoid overflow a2 = a2.clip(0,255) # you must convert back to uint8 /before/ converting to an image img2 = Image.fromarray(a2.astype('uint8')) img2.save('daisy2.png') 

Hope this helps. Now I see why you were disappointed with the results of PIL. Wolfram Mathworld is a good resource for updating vector algebra.

Before

alt text

After

alt text

+8
source share

To increase the depth of the embossing filter, increase the radius of the filter mask. Low depth:

 h = [[1, 0, 0] [0, 0, 0] [0, 0, -1]] 

against great depth:

 h = [[1, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, -1]] 

To change the azimuth, place non-zero coefficients at a different angle:

 h = [[0, 0, 1] [0, 0, 0] [-1, 0, 0]] 

I'm not sure about the height. You may need to change non-zero coefficient values? I just know that this should be a high pass filter.

In any case, to calculate and display an image using the Scipy solution:

 import scipy.misc, scipy.signal im = scipy.misc.imread(filename) im_out = scipy.signal.convolve2d(im, h, 'same') scipy.misc.imshow(im_out) 

Hope this helps.

EDIT: Well, as Paul hinted at PIL, you can adjust the filter options or even define a completely new kernel. The scale and offset options have nothing to do with what you are looking for. Filter size is most important for depth adjustment.

Upon further investigation, PIL does not allow the filter to be resized beyond 5x5. Seems strange. This way, you will not get such a drastic change in depth as you probably expect.

For complete control, you can try the Scipy solution by me and Paul mentioned earlier. Resize the filter to something funny, like 21x21, and see if it makes the type of difference you want.

+2
source share

All Articles