beta.blog

Go: Comic Filter Effect

by on Oct.06, 2023, under News

A comic like filter

A comic filter is a digital graphical effect applied to photos or videos to make them resemble hand-drawn comic book illustrations. This transformation often involves several steps to achieve a stylized, artistic appearance typical of comic art.

Initially, the filter simplifies the image’s colors, reducing them to a limited palette that mirrors the flat shading seen in many comic books. This process, called color quantization, removes subtle gradients and shadows, turning them into block colors.

Next, the filter accentuates edges and outlines in the image, making them bold and dark, resembling the inked lines in comic book art. This is usually achieved through edge detection algorithms that highlight abrupt changes in color or brightness. The result is thick, dark lines surrounding objects, facial features, and other details, adding depth and making them stand out, much like the work of a comic book inker.

Additionally, some comic filters might introduce halftone patterns, those tiny dots seen in older comic prints, to give a vintage feel. Others might add paper textures, exaggerated shadows, or even speech bubbles for added effect.

Overall, a comic filter transforms ordinary photos, giving them a whimsical, hand-drawn appearance reminiscent of classic comic book pages.

package main

import (
	"fmt"
	"image/color"

	"github.com/disintegration/imaging"
)

// Convert hex string to NRGBA color
func hexToNRGBA(hex string) color.NRGBA {
	var c uint32
	fmt.Sscanf(hex, "#%06x", &c)
	return color.NRGBA{
		R: uint8(c >> 16),
		G: uint8(c >> 8),
		B: uint8(c),
		A: 255,
	}
}

// Function to quantize the pixel to the nearest color in the palette.
func quantizeToNearest(c color.NRGBA, palette []color.NRGBA) color.NRGBA {
	var minDist float64 = 1e9
	var bestMatch color.NRGBA

	for _, col := range palette {
		dist := colorDistance(c, col)
		if dist < minDist {
			minDist = dist
			bestMatch = col
		}
	}
	return bestMatch
}

func colorDistance(c1, c2 color.NRGBA) float64 {
	rDiff := float64(c1.R) - float64(c2.R)
	gDiff := float64(c1.G) - float64(c2.G)
	bDiff := float64(c1.B) - float64(c2.B)
	return rDiff*rDiff + gDiff*gDiff + bDiff*bDiff
}

func main() {
	inputPath := "image.jpg"
	outputPath := "image_comic.jpg"

	// Open the image from file
	src, err := imaging.Open(inputPath)
	if err != nil {
		panic(err)
	}

	// Define the color palette
	palette := []color.NRGBA{
		// generic
		hexToNRGBA("#c5131e"),
		hexToNRGBA("#c7242e"),
		hexToNRGBA("#f08327"),
		hexToNRGBA("#538adc"),
		hexToNRGBA("#2859b6"),

		// skin
		hexToNRGBA("#F7E6E3"),
		hexToNRGBA("#EAB486"),
		hexToNRGBA("#E59F6C"),
		hexToNRGBA("#DE804E"),
		hexToNRGBA("#DC7542"),
		hexToNRGBA("#8E2E21"),
		hexToNRGBA("#5C1A19"),

		// black/white
		hexToNRGBA("#000000"),
		hexToNRGBA("#FFFFFF"),
	}

	// Quantize image
	quantized := imaging.AdjustFunc(src, func(c color.NRGBA) color.NRGBA {
		return quantizeToNearest(c, palette)
	})

	// Save the result
	err = imaging.Save(quantized, outputPath)
	if err != nil {
		panic(err)
	}
}
:

Leave a Reply

*

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!