creativescala / doodle

Compositional vector graphics in Scala / Scala.JS
https://creativescala.org/doodle/
Apache License 2.0
327 stars 75 forks source link

Add bitmap convolution operations #94

Open noelwelsh opened 4 years ago

noelwelsh commented 4 years ago

Overview

Convolution is useful for image processing tasks, such as smoothing and edge detection, as well as being a creative tool. An example of what can be achieved using convolutions, and other image processing effects, is given at https://www.smashingmagazine.com/2015/05/why-the-svg-filter-is-awesome/

The goal of this task is to add convolutions to Doodle. Both Java2D and SVG support convolutions, but in different ways. Thus this task requires some API design work. For example, it might make more sense to have different algebras for the different backends.

Details

Convolutions typically apply to rectangular bitmaps, while pictures in Doodle can have arbitrary boundaries and are usually represented a vector shapes, not bitmaps. This means there are several implementation options:

  1. Convolutions apply to an entire Canvas and cannot be applied to individual elements. A convolution is only applied once a Picture is rendered to screen and applies to everything that is rendered.
  2. Convolutions apply to individual elements (a Picture). On the Java2D backend this will require rendering an element to a bitmap buffer, performing the convolution, and then rendering the bitmap ("compositing") back into the main image. In SVG this is directly supported.
  3. There could be an explicit representation of a bitmap (see #85, #87, and #93 for related issues) on which convolutions are applied, and then methods to transform this bitmap to and from a Picture. This achieves the same effect as 2 but is more explicit and will be difficult to support on SVG.

A convolution algebra may look something like the below. This example corresponds to option 3 above, with an explicit representation of a Bitmap.

final case class Kernel(/* Some representation here */)

trait Convolve[Bitmap]{
  def convolve(bitmap: Bitmap, kernel: Kernel): Bitmap
}

See backend specific details:

A few notes:

See #85 for a related issue.