コード例 #1
0
def perlinNoise(size=(256,256),octaves=None,seed=None):
    """
    generate perlin noise
    """
    if octaves is None:
        octaves=math.log(max(size),2.0)
    ret=np.zeros(size)
    for n in range(1,int(octaves)):
        k=n
        amp=1.0#/octaves/float(n)
        px=randomNoise((size[0]/k,size[1]/k),seed)
        px=scipy.ndimage.zoom(px,(float(ret.shape[0])/px.shape[0],float(ret.shape[1])/px.shape[1]),order=2)
        px=np.clip(px,0.0,1.0) # unfortunately zoom function can cause values to go out of bounds :(
        ret=(ret+px*amp)/2.0 # average with existing
    ret=np.clip(ret,0.0,1.0)
    return ret
コード例 #2
0
def curves(image,
           controlPoints,
           clampBlack=0,
           clampWhite=1,
           degree=None,
           extrapolate=True):
    """
    Perform a curves adjustment on an image

    :param image: evaluate the curve at these points can be pil image or numpy array
    :param controlPoints: set of [x,y] points that define the mapping
    :param clampBlack: clamp the black pixels to this value
    :param clampBlack: clamp the white pixels to this value
    :param degree: polynomial degree (if omitted, make it the same as the
        number of control points)
    :param extrapolate: go beyond the defined area of the curve to get values
        (oterwise returns NaN for outside values)

    :return: the adjusted image
    """
    import scipy.interpolate
    img = numpyArray(image)
    count = len(controlPoints)
    if degree is None:
        degree = count - 1
    else:
        degree = np.clip(degree, 1, count - 1)
    knots = np.clip(np.arange(count + degree + 1) - degree, 0, count - degree)
    spline = scipy.interpolate.BSpline(knots, controlPoints, degree)
    if len(img.shape) < 3:
        # for some reason it keeps the original point, which we need to strip off
        resultPoints = spline(img[:, :], extrapolate=extrapolate)[:, :, 0]
    else:
        # for some reason it keeps the original point, which we need to strip off
        resultPoints = spline(img[:, :, :], extrapolate=extrapolate)[:, :, :,
                                                                     0]
    resultPoints = clampImage(resultPoints, clampBlack, clampWhite)
    return pilImage(resultPoints)
コード例 #3
0
def _blendArray(front, back, fn, opacity: float = 1.0):
    """
    :param fn: represents the B function from from the adobe blend modes documentation.
        It takes two parameters, Cb - the background pixels, and Cs - the source pixels
        The documentation originally appeared http://www.adobe.com/devnet/pdf/pdfs/blend_modes.pdf
        Copy included in source. (TODO: remove for copyright reasons?)
    :param opacity: blend mode opacity

    NOTE: always creates new image
    """
    shift = 255.0
    useOpacity = False
    # find some common ground
    w = max(front.width, back.width)
    h = max(front.height, back.height)
    if front.width < w or front.height < h:
        front = extendImageCanvas(front, (0, 0, w, h))
    if back.width < w or back.height < h:
        back = extendImageCanvas(back, (0, 0, w, h))
    mode = maxMode(front, back)
    if front.mode != mode:
        front = front.convert(mode)
    if back.mode != mode:
        back = back.convert(mode)
    # convert to array
    front = np.asarray(front) / shift
    back = np.asarray(back) / shift
    # calculate the alpha channel
    comp_alpha = np.maximum(
        np.minimum(front[:, :, 3], back[:, :, 3]) * opacity, shift)
    new_alpha = front[:, :, 3] + (1.0 - front[:, :, 3]) * comp_alpha
    np.seterr(divide='ignore', invalid='ignore')
    alpha = comp_alpha / new_alpha
    alpha[alpha == np.NAN] = 0.0
    # blend the pixels
    combined = fn(front[:, :, :3], back[:, :, :3]) * shift
    combined = np.clip(combined, 0.0, 255.0)
    # clean up and reassemble
    #ratio_rs =
    final = np.reshape(
        combined, [combined.shape[0], combined.shape[1], combined.shape[2]])
    #final = combined * ratio_rs + front[:, :, :3] * (1.0 - ratio_rs)
    if useOpacity:
        final = np.dstack((final, alpha))
    # convert back to PIL image
    if useOpacity:
        final = Image.fromarray(final.astype('uint8'), mode)
    else:
        final = Image.fromarray(final.astype('uint8'), 'RGB')
    return final
コード例 #4
0
def clampImage(img, minimum=None, maximum=None):
    """
    Clamp an image's pixel to a valid color range

    :param img: clamp a numpy image to valid pixel values can be a PIL image for "do nothing"
    :param minimum: minimum value to clamp to (default is 0)
    :param maximum: maximum value to clamp to (default is the maximum pixel value)
    """
    if minimum is None:  # assign default
        if isFloat(img):
            minimum = 0.0
        else:
            minimum = 0
    elif isFloat(minimum) != isFloat(
            img):  # make sure it matches the image's number space
        if isFloat(minimum):
            minimum = int(minimum * 255)
        else:
            minimum = minimum / 255.0
    if maximum is None:  # assign default
        if isFloat(img):
            maximum = 1.0
        else:
            maximum = 255
    elif isFloat(maximum) != isFloat(
            img):  # make sure it matches the image's number space
        if isFloat(maximum):
            maximum = int(maximum * 255)
        else:
            maximum = maximum / 255.0
    if isinstance(img, np.ndarray):
        if minimum == 0 and (maximum >= 255 or
                             (maximum >= 1.0 and isFloat(maximum))):
            # because conversion implies clamping to a valid range
            return img
        img = numpyArray(img)
    #print(img.shape,minimum,maximum)
    return np.clip(img, minimum, maximum)
コード例 #5
0
def valueRotate(img, amount=0.5):
    """
    Rotate the values, wrapping around at the beginning
    """
    return np.mod(np.clip(img, 0.0, 1.0) + amount, 1.0)
コード例 #6
0
 def trapez(y,y0,w):
     return np.clip(np.minimum(y+1+w/2-y0, -y+1+w/2+y0),0,1)
コード例 #7
0
def section(img,minVal=0.0,maxVal=1.0):
    """
    clamp the values of an image to a given range
    """
    return normalize(np.clip(img,minVal,maxVal))
コード例 #8
0
def generalBlend(topImage,
                 mathStr,
                 botImage,
                 opacity=1.0,
                 position=(0, 0),
                 resize=True):
    """
    mathstr -
        operators:
            basic math symbols ()*/%-+&|
            comparison operators == <= >= && || !=
            comma as combining operator
        functions: abs() sqrt() pow() min() max() count() sum() sin() cos() tan()
            if(condition,then,else)
        images: top, bot
        channel: RGB, CMYK, HSV, A
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Notes:
            * Case sensitive
            * All values are percent values from 0..1
            * After this operation, values will be cropped to 0..1
            * Functions have two modes.
                They work between two channels if two given.
                If one given, they work on all values of that channel.
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Examples:
            RGB=top.RGB/bottom.RGB ... simple divide blend mode
            RGB=min(topRGB,bottomRGB) ... min blend mode
            RGB=(topRGB-min(topRGB)) ... use min in the other mode to normalize black values
            A=1-topV ... extract inverted black levels to alpha channel
            RGBA=topRGB/bottomRGB,1-topV ... use commas to specify different
                operations for different channels
    """
    shift = 255.0
    mathStr = mathStr.replace('\n', '').replace(' ', '').replace('\t', '')
    resultForm, equation = mathStr.split('=', 1)
    # find some common ground
    w = max(topImage.width, botImage.width)
    h = max(topImage.height, botImage.height)
    if topImage.width < w or topImage.height < h:
        topImage = extendImageCanvas(topImage, (0, 0, w, h))
    if botImage.width < w or botImage.height < h:
        botImage = extendImageCanvas(botImage, (0, 0, w, h))
    mode = 'RGBA'  #maxMode(topImage,botImage)
    if topImage.mode != mode:
        topImage = topImage.convert(mode)
    if botImage.mode != mode:
        botImage = botImage.convert(mode)
    # convert to arrays
    topRGBA = np.asarray(topImage) / shift
    for tag in 'HSV':
        if equation.find('top' + tag) >= 0:
            topHSV = rgb2hsvArray(topRGBA)
            break
    for tag in 'CMYK':
        if equation.find('top' + tag) >= 0:
            topCMYK = rgb2cmykArray(topRGBA)
            break
    botRGBA = np.asarray(botImage) / shift
    for tag in 'HSV':
        if equation.find('bottom' + tag) >= 0:
            botHSV = rgb2hsvArray(botRGBA)
            break
    for tag in 'CMYK':
        if equation.find('bottom' + tag) >= 0:
            botCMYK = rgb2cmykArray(botRGBA)
            break
    # convert the equation into python code
    import re
    tokenizer = re.compile(r"([!<>=|&]+|[,()%*-+/])")
    equation = tokenizer.split(equation)
    replacements = {
        'min': 'np.minimum',
        'max': 'np.maximum',
        'abs': 'np.abs',
        'sqrt': 'np.sqrt',
        'pow': 'np.pow',
        'count': 'np.count',
        'sum': 'np.sum',
        'sin': 'np.sin',
        'cos': 'np.cos',
        'tan': 'np.tan',
        'if': 'np.where',
        'top.RGBA': 'topRGBA[:,:,:]',
        'top.RGB': 'topRGBA[:,:,:3]',
        'top.R': 'topRGBA[:,:,0]',
        'top.G': 'topRGBA[:,:,1]',
        'top.B': 'topRGBA[:,:,2]',
        'top.A': 'topRGBA[:,:,3]',
        'top.CMYK': 'topCMYK[:,:,:]',
        'top.CMY': 'topCMYK[:,:,:3]',
        'top.C': 'topCMYK[:,:,0]',
        'top.M': 'topCMYK[:,:,1]',
        'top.Y': 'topCMYK[:,:,2]',
        'top.K': 'topCMYK[:,:,3]',
        'top.HSV': 'topHSV[:,:,:]',
        'top.H': 'topHSV[:,:,0]',
        'topS': 'topHSV[:,:,1]',
        'topV': 'topHSV[:,:,2]',
        'bottom.RGBA': 'bottomRGBA[:,:,:]',
        'bottom.RGB': 'bottomRGBA[:,:,:3]',
        'bottom.R': 'bottomRGBA[:,:,0]',
        'bottom.G': 'bottomRGBA[:,:,1]',
        'bottom.B': 'bottomRGBA[:,:,2]',
        'bottom.A': 'bottomRGBA[:,:,3]',
        'bottom.CMYK': 'bottomCMYK[:,:,:]',
        'bottom.CMY': 'bottomCMYK[:,:,:3]',
        'bottom.C': 'bottomCMYK[:,:,0]',
        'bottom.M': 'bottomCMYK[:,:,1]',
        'bottom.Y': 'bottomCMYK[:,:,2]',
        'bottom.K': 'bottomCMYK[:,:,3]',
        'bottom.HSV': 'bottomHSV[:,:,:]',
        'bottom.H': 'bottomHSV[:,:,0]',
        'bottom.S': 'bottomHSV[:,:,1]',
        'bottom.V': 'bottomHSV[:,:,2]',
    }
    for i, val in enumerate(equation):
        if val and val[0] not in r'0123456789,()%*-+/!<>=|&':
            if val not in replacements:
                raise Exception('ERR: illegal value in equation "' + val + '"')
            equation[i] = replacements[val]
    equation = '(' + (''.join(equation)) + ')'
    # run the operation and join the results with dstack()
    final = None
    for channelSet in eval(equation):
        if final is None:
            final = channelSet
        else:
            final = np.dstack((final, channelSet))
    # convert to RGB colorspace if necessary
    if resultForm == 'HSV':
        final = hsv2rgbArray(final)
    elif resultForm == 'CMYK':
        final = cmyk_to_rgb(final)
    final = final * shift
    # if alpha channel was missing, add one
    if len(final[0][1]) < 4:
        # calculate the alpha channel
        comp_alpha = np.maximum(
            np.minimum(topRGBA[:, :, 3], botRGBA[:, :, 3]) * opacity, shift)
        new_alpha = topRGBA[:, :, 3] + (1.0 - topRGBA[:, :, 3]) * comp_alpha
        np.seterr(divide='ignore', invalid='ignore')
        alpha = comp_alpha / new_alpha
        alpha[alpha == np.NAN] = 0.0
        # blend the pixels
        combined = final
        combined = np.clip(combined, 0.0, 255.0)
        # clean up and reassemble
        #ratio_rs=
        final = np.reshape(
            combined,
            [combined.shape[0], combined.shape[1], combined.shape[2]])
        #final=combined*ratio_rs+topRGBA[:,:,:3]*(1.0-ratio_rs)
        final = np.dstack((final, alpha))
    # convert the final result back into a PIL image
    final = Image.fromarray(final.astype('uint8'), mode)
    return final