0
votes

I'm going to use Wand to cut out some parts of an image. The image has a transparent background. But before I cut out the parts, I first want to make some adjustments to the source image (without actually altering the source file).

The adjustments I want to make are:

  1. Change the black point to gray and leave the white point white
  2. Scale all color values to the new range of gray and white
  3. Replace the transparant background with 100% black
  4. Transform the image into grayscale

I can get the desired result using a simple command with ImageMagick:

convert input.png +clone +level-colors gray,white -background black -alpha remove -colorspace Gray output.png

But how do I do this using Wand? It seems that there's no way to apply the +level-colors operation from Wand. Also the solution from this question: Is there a -level function in wand-py doesn't apply to my problem, I guess. Because it seems the magick image API doesn't have a level-colors method.

Example result of the effect:

Input: Before Output: After

5
You have posted a JPEG rather than a PNG so there are no transparent pixels.... please post the correct starting image.Mark Setchell
Actually I did upload a PNG with transparency but the upload service made it into a jpg. At least the images illustrate the effect I'm after.Jip

5 Answers

2
votes

The -level-colors behavior can be applied by wand.image.Image.level method, but will need to be executed for each color channel. The two colors provided are used as reference black/white points.

For example...

from wand.image import Image
from wand.color import Color
from wand.compat import nested

with Image(filename='rose:') as rose:
    # -level-colors red,green
    with nested(Color('red'),
                Color('green')) as (black_point,
                                    white_point):
        # Red channel
        rose.level(black_point.red,
                   white_point.red,
                   1.0,
                   'red')
        # Green channel
        rose.level(black_point.green,
                   white_point.green,
                   1.0,
                   'green')
        # Blue channel
        rose.level(black_point.blue,
                   white_point.blue,
                   1.0,
                   'blue')
    rose.save(filename='output.png')

-level-colors

For +level-colors, just invert the black/white points.

rose.level(white_point.red,
           black_point.red,
           1.0,
           'red')
1
votes

Since your output image is grey anyway, you don't really need +level-colors, you can do the same thing like this:

convert movies.png -channel RGB -colorspace gray +level 50,100% -background black -alpha remove output.png

Another option may be to use the -fx operator. If you imagine your pixel brightnesses vary between 0 (black) and 1 (white), then if you divide all the brightnesses by 2, they will vary between 0 and 0.5. Then if you add 0.5, they will vary between 0.5 (mid-grey) and 1 (white) - which is what you want:

convert movies.png -channel RGB -colorspace gray -fx "(u/2)+0.5" -background black -alpha remove output.png
0
votes

fmw42 specified a way to implement the +level operation in Wand, using the polynomial function, in A way to perform the +level ImageMagick operation in Wand?.

I have applied fmw42's solution to create a function that performs the +level-colors operation.

from wand.image import Image

#wand_imageToColorize should be an instance of wand.image.Image.
#i_listRgbRangeLowerLimits = [iRedLowerLimit, iGreenLowerLimit, iBlueLowerLimit]
#i_listRgbRangeUpperLimits = [iRedUpperLimit, iGreenUpperLimit, iBlueUpperLimit]
def Colorize(wand_imageToColorize,
             i_listRgbRangeLowerLimits, i_listRgbRangeUpperLimits):
    #input assurance
    for iIndex in range(0, 3):
        if i_listRgbRangeLowerLimits[iIndex] > \
            i_listRgbRangeUpperLimits[iIndex]:
            iTemp = i_listRgbRangeLowerLimits[iIndex]
            i_listRgbRangeLowerLimits[iIndex] = i_listRgbRangeUpperLimits[iIndex]
            i_listRgbRangeUpperLimits[iIndex] = iTemp

        if i_listRgbRangeLowerLimits[iIndex] < 0:
            i_listRgbRangeLowerLimits[iIndex] = 0

        if i_listRgbRangeUpperLimits[iIndex] > 255:
            i_listRgbRangeUpperLimits[iIndex] = 255

    #perform colorization
    str_tupleChannelNames = ('red', 'green', 'blue')

    for iColorComponentIndex in range(0, 3):
        strChannelName = str_tupleChannelNames[iColorComponentIndex]

        fB = float(i_listRgbRangeLowerLimits[iColorComponentIndex]) / 255.0
        fA = float(i_listRgbRangeUpperLimits[iColorComponentIndex]) / 255.0 - fB

        wand_imageToColorize.function('polynomial', [fA, fB], strChannelName)
0
votes

Your command makes no sense. The +clone cause two identical output images. Normally cloning requires it to be in a set of parenthesis.

So perhaps you meant

convert input.png +level-colors gray,white -background black -alpha remove -colorspace Gray output.png


I can achieve something similar to what you have apart from the fact that your image is JPG and not PNG, by

convert input.jpg -colorspace gray -evaluate add 50% result.jpg


enter image description here

A little adjustment of the value (50%) could make it closer.

See wand.image.EVALUATE_OPS at http://docs.wand-py.org/en/0.5.1/wand/image.html for the -evaluate add 50%

0
votes

My other answer is probably simpler and does the job in question. But here is a formal way to do +level-colors by using -clut.

For example:

Input:

enter image description here


Here is +level-colors

convert lenag.png +level-colors red,blue lenag_levelcolors.png


enter image description here

Using -clut, you can get pretty close though not a perfect match.

convert lenag.png \( -size 1x1 xc:red xc:blue +append -filter cubic -resize 256x1! \) -clut lenag_rb4.png


enter image description here

For the OP original processing, one could then do:

convert input.jpg -colorspace gray \( -size 1x1 xc:gray xc:white +append -filter cubic -resize 256x1! \) -clut output.jpg


enter image description here

See Wand clut at http://docs.wand-py.org/en/0.5.1/wand/image.html