Have fun . Oh and do tell me about possible improvements or bugs you encountered.
pip install streamlit-drawable-canvas
app.py
import streamlit as st
from streamlit_drawable_canvas import st_canvas
st.title("Drawable Canvas")
st.markdown("""
Draw on the canvas, get the image data back into Python !
* Doubleclick to remove the selected object when not in drawing mode
""")
st.sidebar.header("Configuration")
# Specify brush parameters and drawing mode
b_width = st.sidebar.slider("Brush width: ", 1, 100, 10)
b_color = st.sidebar.beta_color_picker("Enter brush color hex: ")
bg_color = st.sidebar.beta_color_picker("Enter background color hex: ", "#eee")
drawing_mode = st.sidebar.checkbox("Drawing mode ?", True)
# Create a canvas component
image_data = st_canvas(
b_width, b_color, bg_color, height=150, drawing_mode=drawing_mode, key="canvas"
)
# Do something interesting with the image data
if image_data is not None:
st.image(image_data)
Thanks for the component. This is actually what I was looking for!
I was planning to experiment with a handwriting recognition tool with Streamlint.
I have an issue with the component, only 1/4 top-left section of the canvas appears on the image.
I pasted your code in this post (Iāve tried your code in the github as well), output is same.
When I inspect the canvas code, I saw the double sizes in the code for canvas element as follows:
It should be 600x150 but the in the html below it is 1200x300.
It looks like an issue with the CSS pixel ratio (or devicePixelRatio) that I have yet to implement.
If your screen has a pixel ratio of 2:1 (like an apple screen) then I think Iām expecting this to be the behavior, I did not yet use this ratio to resize the output image from the component. Are you able to you confirm the devicePixelRatio of your screen ?
Iāve also updated the code in the post to be the same as the Github project.
EDIT : oh I can simulate a Retina display with the browser, i get the same behavior as yours Iāll try to debug it in the next days
Hey @fatihkurtoglu, I released a new build which disables Retina scaling, I donāt know if it will make things blurry on your side, Iād be grateful if you could test this !
Hope i did not miss anything, but do you think it might be possible to have a ādefaultā background image to manipulate / draw on?
This would be very helpful in creating human-in-the-loop models, e.g. where a model outputs some predicted segmentation map for unlabeled data, the user interactively cleans the segmentation map and retrains the model with the additional data.
I already tried to pass an encoded image to background_color, because of this answer but sadly i could not get it to work.
Kind regards and thank you for your awesome work again.
This is also something I have in mind and tracked here. Donāt hesitate to track it! Iāll be giving it a shot this week.
Thanks for explaining your usecase, it helps design the API and maybe change the underlying canvas library XD. Right now my 2 thoughts on this:
What would be the ideal Python type of the background image you want to send ?
I think right now, if I implemented the setBackgroundImage, when you draw on the canvas it would send you the image + the drawing, Iām not sure thatās what we want. Whatās your opinion on this ?
The ideal python type of the background image would be maybe a PIL.Image? If we send a raw numpy array, the component would have to guess the image type.
The ultimate solution would be a layered approach. Along the lines of add_layer(img=None). For drawing, one would need to select the active layer Defaulting to the last layer or first layer would be enough in most use cases. The compent then always returns the active layer as a numpy array, like currently implemented. Not sure though if this layered approach is feasible to add retrospectively.
Thanks for your quick reply and your time!
Cheers.
Hi @andfanilo ,
I was trying out the Drawable canvas and tried out the code for the example shown above.
I have two questions:
canvas_result.image_data -> Is there a streamlit function to save this array as an image file (.jpg, png etc) ?
The numpy arrayās shape is (100,100,4) where, 100 -> canvas size
i.e. print(canvas_result.image_data.shape)
Shouldnāt the shape be 100,100,3 , i.e. for 3 channels? I didnāt understand why this value is 4.
The image_data is a numpy array with 3 color channel + 1 alpha channelā¦even though I havenāt implemented any opacity channel yet in the brush coloring so I guess the 4th channel should be 1 everywhere.
The HTML canvas sends me back a byte array of height x width x RGBA so by default I kept the Alpha channel. You can dump this channel in your application.
Pillow is installed by the package so :
from Pillow import Image
im = Image.fromarray(img_data)
im.save(file_path, "JPEG")
Just wanted to come back and congrat you on the latest realse of drawable-canvas. I could sucessfully build a labeling pipeline for our internal projects. Thank you so much.
@andfanilo , how can I predraw some shapes on @streamlit canvas such as square, rectangle, traingle or some icon(say smartphone icon). I do not want the user to use his mouse to create these shapes on the canvas. Basically I want to draw these shapes automaticaly at random places in the canvas based on some other actions by user such as his age, gender, etc.
Thanks for much for your code. I had a quick question. When I look at the output of the rectangular (json), it doesnāt seem to update the width and height if I use the transform function. The rectangular on the images is updated but not the value in the json.
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking āAccept allā, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.