Image Processing Library

### Introduction

KYky is a programming language that allows for easy and efficient image processing. The language provides a set of functions that enable image manipulation, filtering, compression, and more. This library is particularly useful for tasks such as face detection, image enhancement, and noise reduction. It is also ideal for tasks that require complex operations such as convolution filtering and color balance adjustment.

The library provides a range of functions for image processing, including image loading, saving, and resizing. It also provides functions for rotating, flipping, and cropping images, as well as adjusting brightness, contrast, and color balance. KYky's library also provides a range of filter functions, including blur filters, sharpen filters, edge detection filters, and noise reduction filters.

The KYky library is built using several popular Python libraries, including Pillow (PIL) and OpenCV, as well as numpy and scipy. This allows users to benefit from the capabilities of these libraries while working within the KYky programming language. The library's functions are designed to be efficient, making it possible to process large numbers of images quickly and easily.

In summary, KYky Programming Language's Image Processing Library is a powerful tool for any developer or data scientist working with images. It provides a range of functions for image processing and filtering, making it ideal for tasks such as face detection, image enhancement, and noise reduction. Its efficient design ensures that images can be processed quickly and easily, making it an excellent choice for working with large datasets.

### Prototype

```
from PIL import Image, ImageFilter, ImageEnhance
import numpy as np
from scipy.signal import convolve2d
import cv2

def load_image(filename):
    """Load an image from a file into memory."""
    return Image.open(filename)

def save_image(image, filename):
    """Save an image to a file."""
    image.save(filename)

def resize_image(image, width, height, resample=Image.LANCZOS):
    """Resize an image to a new width and height."""
    return image.resize((width, height), resample=resample)

def rotate_image(image, angle, resample=Image.BILINEAR):
    """Rotate an image by a specified angle."""
    return image.rotate(angle, resample=resample)

def flip_image(image, axis):
    """Flip an image along a specified axis (horizontal or vertical)."""
    if axis == 'horizontal':
        return image.transpose(method=Image.FLIP_LEFT_RIGHT)
    elif axis == 'vertical':
        return image.transpose(method=Image.FLIP_TOP_BOTTOM)
    else:
        raise ValueError('Invalid axis value, should be "horizontal" or "vertical".')

def adjust_brightness(image, level):
    """Adjust the brightness of an image by a specified level."""
    enhancer = ImageEnhance.Brightness(image)
    return enhancer.enhance(level)

def adjust_contrast(image, level):
    """Adjust the contrast of an image by a specified level."""
    enhancer = ImageEnhance.Contrast(image)
    return enhancer.enhance(level)

def adjust_color_balance(image, levels):
    """Adjust the color balance of an image by specifying the levels of each color channel (red, green, and blue)."""
    r, g, b = image.split()
    r = ImageEnhance.Color(r).enhance(levels[0])
    g = ImageEnhance.Color(g).enhance(levels[1])
    b = ImageEnhance.Color(b).enhance(levels[2])
    return Image.merge('RGB', (r, g, b))

def apply_filter(image, kernel):
    """Apply a convolution filter to an image using a specified kernel."""
    img_array = np.array(image)
    img_filtered = np.zeros_like(img_array)
    for i in range(3):
        img_filtered[:,:,i] = convolve2d(img_array[:,:,i], kernel, mode='same', boundary='symm')
    return Image.fromarray(img_filtered)

def compress_image(image, format):
    """Compress an image using a specified format (e.g., JPEG, PNG)."""
    image.save('temp.jpg', format=format, quality=95)
    compressed_image = Image.open('temp.jpg')
    return compressed_image

def crop_image(image, left, top, right, bottom):
    """Crop an image."""
    return image.crop((left, top, right, bottom))

def apply_blur_filter(image, size):
    """Apply a blur filter to an image using a specified kernel."""
    kernel = np.ones((size, size), dtype=np.float32) / (size ** 2)
    return apply_filter(image, kernel)

def apply_sharpen_filter(image, strength):
    """Apply a sharpen filter to an image using a specified kernel."""
    kernel = np.array([[-1, -1, -1], [-1, strength+8, -1], [-1, -1, -1]]) / strength
    return apply_filter(image, kernel)

def apply_edge_detection_filter(image):
    kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])
    return apply_filter(image, kernel)

def apply_noise_reduction_filter(image):
    kernel = np.ones((3, 3)) / 9
    return apply_filter(image, kernel)

def load_image(filename):
    return cv2.imread(filename)

def detect_faces(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
    return faces

        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    return image

def convert_to_grayscale(image):
    return image.convert('L')

def apply_gaussian_blur(image, size):
    return image.filter(ImageFilter.GaussianBlur(radius=size))

def apply_emboss_filter(image):
    kernel = np.array([[0, 1, 0], [0, 0, 0], [0, -1, 0]])
    return apply_filter(image, kernel)

def apply_sepia_filter(image):
    r, g, b = image.split()
    r, g, b = np.array(r), np.array(g), np.array(b)
    gray = 0.3 * r + 0.59 * g + 0.11 * b
    r = gray + 40
    g = gray + 20
    b = gray - 20
    r, g, b = np.clip(r, 0, 255), np.clip(g, 0, 255), np.clip(b, 0, 255)
    return Image.fromarray(np.dstack((r, g, b)).astype(np.uint8))

def apply_vignette_filter(image, strength=0.5):
    w, h = image.size
    mask = Image.new("L", (w, h), 0)
    draw = ImageDraw.Draw(mask)
    xy = [(w * strength, h * strength), (w * (1 - strength), h * strength), (w * (1 - strength), h * (1 - strength)), (w * strength, h * (1 - strength))]
    draw.polygon(xy, outline=255, fill=255)
    mask = np.array(mask)[:, :, np.newaxis]
    mask = np.tile(mask, (1, 1, 3))
    return Image.fromarray(np.array(image) * mask)

def grayscale_range(image, lower_bound, upper_bound):
    img_array = np.array(image)
    mask = cv2.inRange(img_array, lower_bound, upper_bound)
    img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
    img_array[mask != 255] = 0
    return Image.fromarray(img_array)

def apply_filter(image, kernel):
    img_array = np.array(image)
    filtered_array = cv2.filter2D(img_array, -1, kernel)
    return Image.fromarray(filtered_array)

def color_quantization(image, k):
    img_array = np.array(image)
    pixel_values = img_array.reshape((-1, 3))
    pixel_values = np.float32(pixel_values)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    _, labels, centers = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    centers = np.uint8(centers)
    result = centers[labels.flatten()]
    result = result.reshape((img_array.shape))
    return Image.fromarray(result)

def apply_sketch_filter(image):
    img_array = np.array(image)
    gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
    inverted = 255 - gray
    blurred = cv2.GaussianBlur(inverted, (21, 21), 0, 0)
    inverted_blurred = 255 - blurred
    pencil_sketch = cv2.divide(gray, inverted_blurred, scale=256.0)
    return Image.fromarray(pencil_sketch)

def convert_to_bw(image):
    return image.convert('1')

def apply_sepia_filter(image):
    sepia = np.array([[0.393, 0.769, 0.189],
                      [0.349, 0.686, 0.168],
                      [0.272, 0.534, 0.131]])
    return apply_filter(image, sepia)

def apply_vignette_effect(image, strength):
    w, h = image.size
    radius = int(np.sqrt((w/2)**2 + (h/2)**2))
    x, y = np.meshgrid(np.linspace(-w/2, w/2, w), np.linspace(-h/2, h/2, h))
    d = np.sqrt(x**2 + y**2)
    vignette = 1 - (d / radius) ** strength
    vignette = np.clip(vignette, 0, 1)
    vignette = np.stack([vignette]*3, axis=2)
    return apply_filter(image, vignette)

def apply_mosaic_effect(image, block_size):
    w, h = image.size
    block_size = max(1, min(w, h, block_size))
    n_blocks_w = w // block_size
    n_blocks_h = h // block_size
    blocks = np.zeros((n_blocks_h, n_blocks_w, 3), dtype=np.uint8)
            block = np.array(image.crop((j*block_size, i*block_size, (j+1)*block_size, (i+1)*block_size)).resize((1, 1)))
            blocks[i, j] = block
    blocks_image = Image.fromarray(blocks.repeat(block_size, axis=0).repeat(block_size, axis=1))
    return resize_image(blocks_image, w, h)

def apply_threshold_filter(image, threshold):
    """Apply a binary threshold filter to an image."""
    gray = image.convert('L')
    return gray.point(lambda x: 255 if x > threshold else 0, '1')

def apply_invert_filter(image):
    """Invert the colors of an image."""
    return ImageOps.invert(image)

def adjust_brightness_and_contrast(image, brightness, contrast):
    """Adjust the brightness and contrast of an image."""
    enhancer = ImageEnhance.Brightness(image)
    image = enhancer.enhance(brightness)
    enhancer = ImageEnhance.Contrast(image)
    return enhancer.enhance(contrast)

def apply_sobel_filter(image):
    """Apply a Sobel filter to an image for edge detection."""
    im = image.convert('L')
    imx = np.zeros_like(im)
    imy = np.zeros_like(im)
    im = np.array(im, dtype='float64')
    imx = np.array(imx, dtype='float64')
    imy = np.array(imy, dtype='float64')
    kernelx = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    kernely = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
            imx[i,j] = np.sum(kernelx * im[i-1:i+2, j-1:j+2])
            imy[i,j] = np.sum(kernely * im[i-1:i+2, j-1:j+2])
    imx = np.abs(imx)
    imy = np.abs(imy)
    return Image.fromarray(np.uint8(imx + imy))

def apply_histogram_equalization(image):
    """Apply histogram equalization to an image."""
    hist, bins = np.histogram(image.flatten(), 256, [0, 256])
    cdf = hist.cumsum()
    cdf_normalized = cdf * hist.max() / cdf.max()
    cdf_m = np.ma.masked_equal(cdf, 0)
    cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
    cdf = np.ma.filled(cdf_m, 0).astype('uint8')
    return Image.fromarray(cdf[image])

def apply_threshold(image, threshold):
    """Apply a threshold to an image to create a binary image."""
    gray = image.convert('L')
    return gray.point(lambda x: 255 if x > threshold else 0, '1')

def apply_dilation_filter(image, kernel):
    """Apply a dilation filter to an image using a specified kernel."""
    img_array = np.array(image)
    img_dilated = np.zeros_like(img_array)
    for i in range(3):
        img_dilated[:,:,i] = cv2.dilate(img_array[:,:,i], kernel)
    return Image.fromarray(img_dilated)

def apply_erosion_filter(image, kernel):
    """Apply an erosion filter to an image using a specified kernel."""
    img_array = np.array(image)
    img_eroded = np.zeros_like(img_array)
    for i in range(3):
        img_eroded[:,:,i] = cv2.erode(img_array[:,:,i], kernel)
    return Image.fromarray(img_eroded)

def apply_median_filter(image, size):
    """Apply a median filter to an image using a specified kernel size."""
    img_array = np.array(image)
    img_median = np.zeros_like(img_array)
    for i in range(3):
        img_median[:,:,i] = cv2.medianBlur(img_array[:,:,i], size)
    return Image.fromarray(img_median)

def apply_bilateral_filter(image, d, sigmaColor, sigmaSpace):
    """Apply a bilateral filter to an image using a specified parameters."""
    img_array = np.array(image)
    img_filtered = cv2.bilateralFilter(img_array, d, sigmaColor, sigmaSpace)
    return Image.fromarray(img_filtered)

def detect_lines(image, threshold, minLineLength, maxLineGap):
    """Detect lines in an image using a Hough Transform."""
    gray = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold, minLineLength=minLineLength, maxLineGap=maxLineGap)
    return lines

def draw_lines(image, lines, color=(0, 0, 255), thickness=2):
    """Draw lines on an image."""
    img = np.array(image)
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(img, (x1, y1), (x2, y2), color, thickness)
    return Image.fromarray(img)

def apply_canny_edge_detection(image, threshold1, threshold2):
    """Apply a Canny edge detection filter to an image using specified thresholds."""
    gray = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, threshold1, threshold2)
    return Image.fromarray(edges)

def apply_vignette_effect(image, radius, darkness):
    """Apply a vignette effect to an image by darkening the corners."""
    x, y = np.meshgrid(np.linspace(-1, 1, image.size[0]), np.linspace(-1, 1, image.size[1]))
    d = np.sqrt(x * x + y * y)
    vignetted = np.interp(d, (d.min(), d.max()), (1 - darkness, 1))
    mask = np.repeat(vignetted[:, :, np.newaxis], 3, axis=2)
    return Image.fromarray((np.array(image) * mask).astype('uint8'))

def apply_pencil_sketch_effect(image):
    """Apply a pencil sketch effect to an image."""
    grayscale_image = convert_to_grayscale(image)
    blurred_image = grayscale_image.filter(ImageFilter.GaussianBlur(radius=3))
    sketch_image = ImageOps.autocontrast(ImageChops.subtract(grayscale_image, blurred_image, scale=256))
    return sketch_image

def apply_watercolor_effect(image, scale=1, blur=5, saturation=1.5):
    """Apply a watercolor effect to an image."""
    scaled_image = image.resize((int(image.size[0] * scale), int(image.size[1] * scale)), resample=Image.LANCZOS)
    blurred_image = scaled_image.filter(ImageFilter.GaussianBlur(radius=blur))
    watercolor_image = ImageEnhance.Color(blurred_image).enhance(saturation)
    return watercolor_image

def apply_glitch_effect(image, shift):
    """Apply a glitch effect to an image by shifting pixels randomly in each row."""
    img_array = np.array(image)
    rows, cols, channels = img_array.shape
    for row in range(rows):
        img_array[row, :, :] = np.roll(img_array[row, :, :], shift)
    return Image.fromarray(img_array)
```