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: