“This is the 25th day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021”

preface

In OpenCV, you can apply cv2.bilateralFilter() to reduce noise while preserving sharp edges. However, this filter will produce step effect and false edges in the filtered image. While this defect can be reduced by improving bilateral filtering, the effect can be used to create cool cartographic images. In this article, we will explore how to implement image cartonization in OpenCV.

Cartoonization of images

To realize the cartoonization of the image, it is necessary to construct the sketch of the image according to the edge of the image.

The sketch_image() function is used to construct the sketch of the image, first converting the color image to a grayscale image, and then smoothing the image with the cv2.medianblur () median filter to reduce noise:

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.medianBlur(img_gray, 5)
Copy the code

Next, the Laplacian operator cv2.laplacian () is used as the edge detector:

edges = cv2.Laplacian(img_gray, cv2.CV_8U, ksize=5)
Copy the code

Next, the edges of the image are used to create a sketch of the image, and the generated image is threshold processed by applying cv2.threshold() (threshold technology will be specifically introduced later, here we only need to know that this function provides us with a binary image from a given grayscale image, As the output of the sketch_image() function). Can use different threshold value to control the results appear in the black pixels in the image (i.e., the edge of the detected) number, if the threshold is small (10), for example, many will appear black pixels, on the other hand if the value is bigger (e.g., 200), then you’ll get a few black pixels, can get oneself satisfactory result through the value:

ret, threshold = cv2.threshold(edges, 145.255, cv2.THRESH_BINARY_INV)
Copy the code

Next, we can write the cartonize_image() function to implement the function of cartooning images.

To get the cartoonish effect, first call the cv2.bilateralFilter() function with a larger value, for example:

cv2.bilateralFilter(img, 10.250.250) 
Copy the code

The second and final step is to combine the sketch image with the output of bilateral filtering using the cv2.bitwise_and() function (bitwise operation), with the sketch image as a mask to ensure the output of these values. The output can also be converted to a grayscale image if desired:

cartoonized = cv2.bitwise_and(filtered, filtered, mask=threshold)

if gray_mode:
    return cv2.cvtColor(cartoonized, cv2.COLOR_BGR2GRAY)
Copy the code

In addition to the above custom functions to achieve image cartoonization, OpenCV also provides a similar built-in function, you can use the following filter to achieve the same function:

  1. cv2.pencilSketch(): This filter generates pencil sketch lines (similar to custom ones)sketch_image()Function)
  2. cv2.stylization(): This filter can be used to produce a variety of non-photorealistic effects that can be appliedcv2.stylization()Get cartoonish effect (similar to customcartonize_image()Function)

The code running result is as follows:

The complete code

The complete code is shown below:

import cv2
import matplotlib.pyplot as plt

def show_with_matplotlib(color_img, title, pos) :
    img_RGB = color_img[:, :, ::-1]

    ax = plt.subplot(2.4, pos)
    plt.imshow(img_RGB)
    plt.title(title, fontsize=10)
    plt.axis('off')

def sketch_image(img) :
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_gray = cv2.medianBlur(img_gray, 5)
    edges = cv2.Laplacian(img_gray, cv2.CV_8U, ksize=5)
    ret, threshold = cv2.threshold(edges, 145.255, cv2.THRESH_BINARY_INV)
    return threshold

# Custom function to achieve cartoon
def cartonize_image(img, gray_mode=False) :
    Extract the middle edge of the image
    threshold = sketch_image(img)
    # Bilateral filtering
    filtered = cv2.bilateralFilter(img, 10.250.250)
    # cartoonish
    cartoonized = cv2.bitwise_and(filtered, filtered, mask=threshold)

    if gray_mode:
        return cv2.cvtColor(cartoonized, cv2.COLOR_BGR2GRAY)
    return cartoonized

plt.figure(figsize=(14.6))
plt.suptitle("Cartoonizing images", fontsize=14, fontweight='bold')

image = cv2.imread('sigonghuiye.jpeg')

custom_sketch_image = sketch_image(image)
custom_cartonized_image = cartonize_image(image)
custom_cartonized_image_gray = cartonize_image(image, True)

# Use OpenCV functions to achieve cartoonization
sketch_gray, sketch_color = cv2.pencilSketch(image, sigma_s=20, sigma_r=0.1, shade_factor=0.1)
stylizated_image = cv2.stylization(image, sigma_s=60, sigma_r=0.07)

show_with_matplotlib(image, "image".1)
show_with_matplotlib(cv2.cvtColor(custom_sketch_image, cv2.COLOR_GRAY2BGR), 'custom sketch'.2)
show_with_matplotlib(cv2.cvtColor(sketch_gray, cv2.COLOR_GRAY2BGR), 'sketch gray cv2.pencilSketch()'.3)
show_with_matplotlib(sketch_color, 'sketch color cv2.pencilSketch()'.4)
show_with_matplotlib(stylizated_image, 'cartoonized cv2.stylization()'.5)
show_with_matplotlib(custom_cartonized_image, 'custom cartoonized'.6)
show_with_matplotlib(cv2.cvtColor(custom_cartonized_image_gray, cv2.COLOR_GRAY2BGR), 'custom cartoonized gray'.7)

plt.show()
Copy the code

More cartoon effect display

We can modify the source image or function parameters to achieve a satisfactory cartooning effect:

Let’s do it.