Skip to content

Add demonstration of bitmafilter.blend #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions adafruit_pycamera/imageprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,123 @@ def emboss_greyscale(bitmap, mask=None):
def ironbow(bitmap, mask=None):
"""Convert an image to false color using the 'ironbow palette'"""
return bitmapfilter.false_color(bitmap, ironbow_palette, mask=mask)


# pylint: disable=invalid-name
def alphablend_maker(frac, nfrac=None):
"""Create an alpha-blending function for a specific fractional value

The resulting function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``.
"""
if nfrac is None:
nfrac = 1 - frac

def inner(a, b):
return frac * a + nfrac * b

return inner


def screen_func(a, b):
"""The 'screen' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return 1 - (1 - a) * (1 - b)


def overlay_func(a, b):
"""The 'overlay' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return 2 * a * b if a < 0.5 else 1 - 2 * (1 - a) * (1 - b)


def hard_light_func(a, b):
"""The 'hard light' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return 2 * a * b if b < 0.5 else 1 - 2 * (1 - a) * (1 - b)


# illusions.hu formula version
def soft_light_func(a, b):
"""The 'soft light' blend mode.

There are various soft light blend functions. The "illusions.hu" variant of
soft light is used.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a ** (2 ** (2 * 0.5 - b))


def color_dodge_func(a, b):
"""The 'color dodge' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a / (1 - b) if b != 1 else 1


def linear_dodge_func(a, b):
"""The 'linear dodge' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a + b


def divide_func(a, b):
"""The 'divide' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a / b if b else 1


def multiply_func(a, b):
"""The 'multiply' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a * b


def subtract_func(a, b):
"""The 'subtract' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a - b


def color_burn_func(a, b):
"""The 'color burn' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a * (1 - b)


def linear_burn_func(a, b):
"""The 'linear burn' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
return a + b - 1


darken_only_func = min
"""The 'darken only' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
lighten_only_func = max
"""The 'screen' blend mode.

This function can be used with ``bitmapfilter.blend`` and
``bitmapfilter.blend_precompute``."""
17 changes: 17 additions & 0 deletions examples/camera/boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

"""Automatically create the /sd mount point at boot time"""

import os
import storage

storage.remount("/", readonly=False)

try:
os.mkdir("/sd")
except OSError:
pass # It's probably 'file exists', OK to ignore

storage.remount("/", readonly=True)
94 changes: 94 additions & 0 deletions examples/filter/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,95 @@
from adafruit_pycamera import imageprocessing
from adafruit_pycamera import PyCameraBase


blend_50_50 = bitmapfilter.blend_precompute(imageprocessing.alphablend_maker(0.5))
screen = bitmapfilter.blend_precompute(imageprocessing.screen_func)
overlay = bitmapfilter.blend_precompute(imageprocessing.overlay_func)
hard_light = bitmapfilter.blend_precompute(imageprocessing.hard_light_func)
soft_light = bitmapfilter.blend_precompute(imageprocessing.soft_light_func)
color_dodge = bitmapfilter.blend_precompute(imageprocessing.color_dodge_func)
# linear_dodge = bitmapfilter.blend_precompute(imageprocessing.linear_dodge_func)
# divide = bitmapfilter.blend_precompute(imageprocessing.divide_func)
multiply = bitmapfilter.blend_precompute(imageprocessing.multiply_func)
# subtract = bitmapfilter.blend_precompute(imageprocessing.subtract_func)
# color_burn = bitmapfilter.blend_precompute(imageprocessing.color_burn_func)
# linear_burn = bitmapfilter.blend_precompute(imageprocessing.linear_burn_func)
# darken_only = bitmapfilter.blend_precompute(min)
# lighten_only = bitmapfilter.blend_precompute(max)


def blender(f):
def inner(b):
return bitmapfilter.blend(b, b, testpattern, f)

return inner


def reverse_blender(f):
def inner(b):
return bitmapfilter.blend(b, testpattern, b, f)

return inner


inverse_greyscale_weights = bitmapfilter.ChannelMixer(
1 - 0.299,
1 - 0.587,
1 - 0.114,
1 - 0.299,
1 - 0.587,
1 - 0.114,
1 - 0.299,
1 - 0.587,
1 - 0.114,
)

blur_more = [
4,
15,
24,
15,
4,
15,
61,
97,
61,
15,
24,
97,
154,
97,
24,
15,
61,
97,
61,
15,
4,
15,
24,
15,
4,
]


# "Sketch" filter based on
# https://www.freecodecamp.org/news/sketchify-turn-any-image-into-a-pencil-sketch-with-10-lines-of-code-cf67fa4f68ce/
def sketch(b):
bitmapfilter.mix(b, inverse_greyscale_weights)
memoryview(auxbuffer)[:] = memoryview(b)
bitmapfilter.morph(auxbuffer, blur_more)
bitmapfilter.blend(b, auxbuffer, b, color_dodge)
bitmapfilter.mix(b, inverse_greyscale_weights) # get rid of magenta halos
return b


effects = [
("sketch", sketch),
("50/50", blender(blend_50_50)),
("multiply", blender(multiply)),
("soft light", blender(soft_light)),
("hard_light", blender(hard_light)),
("blue cast", imageprocessing.blue_cast),
("blur", imageprocessing.blur),
("bright", lambda b: bitmapfilter.mix(b, bitmapfilter.ChannelScale(2.0, 2.0, 2.0))),
Expand Down Expand Up @@ -65,6 +153,9 @@ def cycle(seq):
pycam = PyCameraBase()
pycam.init_display()

testpattern = displayio.Bitmap(208, 208, 65535)
auxbuffer = displayio.Bitmap(208, 208, 65535)


def main():
filename = "/cornell_box_208x208.jpg"
Expand All @@ -74,6 +165,9 @@ def main():
decoder.open(filename)
decoder.decode(bitmap0)

decoder.open("/testpattern_208x208.jpg")
decoder.decode(testpattern)

label = Label(font=FONT, x=0, y=8)
pycam.display.root_group = label
pycam.display.refresh()
Expand Down
Binary file added examples/filter/testpattern_208x208.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions examples/filter/testpattern_208x208.jpg.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries

SPDX-License-Identifier: Unlicense