Character picture is a picture composed of letters, punctuation marks or other characters. It came into being in the Internet era and is widely used in chat software. In this article, we will look at how to turn your favorite picture into character picture.

Static image

First, we will demonstrate the static image into character painting, function implementation mainly use Python library for OpenCV, install using PIP install opencv-python command can be.

The basic idea of function realization is as follows: the pixel information is grouped into 3 or 5 categories by clustering. The category of darkest color is represented by digital intensity, the category of shadow is represented by horizontal bars (-), and the bright part is represented by blank.

The main code is as follows:

def img2strimg(frame, K=5) :   
    if type(frame) ! = np.ndarray: frame = np.array(frame) height, width, *_ = frame.shape frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frame_array = np.float32(frame_gray.reshape(-1))
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10.1.0)
    flags = cv2.KMEANS_RANDOM_CENTERS
    # Get labels, centroids
    compactness, labels, centroids = cv2.kmeans(frame_array, K, None, criteria, 10, flags)
    centroids = np.uint8(centroids)
    The number of # labels are arranged in random order, so we need to deal with the centers of moment simply
    centroids = centroids.flatten()
    centroids_sorted = sorted(centroids)
    Get the degree of lightness of different centroids, 0 being the darkest
    centroids_index = np.array([centroids_sorted.index(value) for value in centroids])
    bright = [abs((3 * i - 2 * K) / (3 * K)) for i in range(1.1 + K)]
    bright_bound = bright.index(np.min(bright))
    shadow = [abs((3 * i - K) / (3 * K)) for i in range(1.1 + K)]
    shadow_bound = shadow.index(np.min(shadow))
    labels = labels.flatten()
    # Convert labels to the actual lightness list
    labels = centroids_index[labels]
    # parse list
    labels_picked = [labels[rows * width:(rows + 1) * width:2] for rows in range(0, height, 2)]
    canvas = np.zeros((3 * height, 3 * width, 3), np.uint8)
	Create a white canvas three times as long and wide as the original
    canvas.fill(255)
    y = 8
    for rows in labels_picked:
        x = 0
        for cols in rows:
            if cols <= shadow_bound:
                cv2.putText(canvas, str(random.randint(2.9)),
                            (x, y), cv2.FONT_HERSHEY_PLAIN, 0.45.1)
            elif cols <= bright_bound:
                cv2.putText(canvas, "-", (x, y),
                            cv2.FONT_HERSHEY_PLAIN, 0.4.0.1)
            x += 6
        y += 6
    return canvas
Copy the code

The original picture is as follows:

The renderings are as follows:

GIF dynamic figure

The main Python libraries used for this function are Imageio and Pillow. PIP install imageio/Pillow command is used to install this function.

The basic idea of function realization is as follows:

  • Split each frame of the GIF image into a still image
  • Turn all static images into character paintings
  • Recompose all character drawings into GIFs

The main code is as follows:

# split GIF processes each frame into a character drawing
def gif2pic(file, ascii_chars, isgray, font, scale) :
    "File: GIF file ascii_chars: string corresponding to gray value isgray: whether black and white font: ImageFont object scale: scale"
    im = Image.open(file)
    path = os.getcwd()
    if(not os.path.exists(path+"/tmp")):
        os.mkdir(path+"/tmp")
    os.chdir(path+"/tmp")
    Clear the TMP directory
    for f in os.listdir(path+"/tmp"):
        os.remove(f)
    try:
        while 1:
            current = im.tell()
            name = file.split('. ') [0] +'_tmp_'+str(current)+'.png'
            # Save each frame
            im.save(name)
            # Process each frame as a character drawing
            img2ascii(name, ascii_chars, isgray, font, scale)
            # Proceed to the next frame
            im.seek(current+1)
    except:
        os.chdir(path)

# Map different gray values to ASCII characters
def get_char(ascii_chars, r, g, b) :
    length = len(ascii_chars)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    return ascii_chars[int(gray/(256/length))]


# Process the picture into character painting
def img2ascii(img, ascii_chars, isgray, font, scale) :
    scale = scale
    Convert the image to RGB mode
    im = Image.open(img).convert('RGB')
    # Set the character drawing size after processing
    raw_width = int(im.width * scale)
    raw_height = int(im.height * scale)
    Get the size of the font
    font_x, font_y = font.getsize(' ')
    # Determine the size of the cell
    block_x = int(font_x * scale)
    block_y = int(font_y * scale)
    # Make sure there are several units of each length and width
    w = int(raw_width/block_x)
    h = int(raw_height/block_y)
    Shrink each cell to one pixel
    im = im.resize((w, h), Image.NEAREST)
    # TXTS and colors store the ASCII characters and RGB values of the corresponding blocks, respectively
    txts = []
    colors = []
    for i in range(h):
        line = ' '
        lineColor = []
        for j in range(w):
            pixel = im.getpixel((j, i))
            lineColor.append((pixel[0], pixel[1], pixel[2]))
            line += get_char(ascii_chars, pixel[0], pixel[1], pixel[2])
        txts.append(line)
        colors.append(lineColor)
    Create a new canvas
    img_txt = Image.new('RGB', (raw_width, raw_height), (255.255.255))
    Create an ImageDraw object to write ASCII
    draw = ImageDraw.Draw(img_txt)
    for j in range(len(txts)):
        for i in range(len(txts[0)) :if isgray:
                draw.text((i * block_x, j * block_y), txts[j][i], (119.136.153))
            else:
                draw.text((i * block_x, j * block_y), txts[j][i], colors[j][i])
    img_txt.save(img)

Create GIF from TMP directory
def pic2gif(dir_name, out_name, duration) :
    path = os.getcwd()
    os.chdir(dir_name)
    dirs = os.listdir()
    images = []
    num = 0
    for d in dirs:
        images.append(imageio.imread(d))
        num += 1
    os.chdir(path)
    imageio.mimsave(out_name + '_ascii.gif',images,duration = duration)
Copy the code

The original picture is as follows:

Black and white renderings are as follows:

The color renderings are as follows:

conclusion

This article uses Python to demonstrate how to convert static images and GIFs into character drawings. If you are interested, you can convert your favorite image. If you are not satisfied with the conversion, you can also modify the code to change the effect to your own satisfaction.

The source code is available in Python.

This article was not originally published in the personal journal