I cannot figure out how to draw a pixel in ipycanvas. I am drawing rectangles instead of pixels and this makes drawing very slow.
Drawing a rectangle using:
canvas.fill_rect
Code to display image in ipycanvas :
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import ipycanvas
from ipycanvas import Canvas
import requests
from io import BytesIO
url = r"https://wallpapercave.com/dwp1x/wp1816238.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))
array = img.tobytes()
canvas = Canvas(width=img.width, height=img.height)
with ipycanvas.hold_canvas():
for i in range(int(len(array)/3)):
r = array[i * 3 + 0] # red
g = array[i * 3 + 1] # green
b = array[i * 3 + 2] # blue
canvas.fill_style = f"#{r:02x}{g:02x}{b:02x}" # setting color
canvas.fill_rect(i%img.width, int(i/img.width), 1, 1) # drawing rectangle
canvas
Output:
I am drawing image pixel by pixel because I want to apply filters in images.
How to draw pixels in ipycanvas?
Not sure if this will help but given you're talking about filtering I'd assume you mean things like convolutions. Numpy and Scipy help a lot and provide various ways of applying these and work well with images from Pillow.
For example:
import requests
from io import BytesIO
from PIL import Image
import numpy as np
from scipy import signal
image_req = requests.get("https://wallpapercave.com/dwp1x/wp1816238.jpg")
image_req.raise_for_status()
image = Image.open(BytesIO(image_req.content))
# create gaussian glur of a given standard deviation
sd = 3
filt = np.outer(*2*[signal.windows.gaussian(int(sd*5)|1, sd)])
filt /= filt.sum()
# interpret image as 3d array
arr = np.array(image)
# apply it to each channel independently, this loop runs in ~0.1 seconds
for chan in range(3):
arr[:,:,chan] = signal.oaconvolve(arr[:,:,chan], filt, mode='same')
# array back into image for display in notebook
Image.fromarray(arr)
This produces an image like: