pycasso: How to build a picture frame to show you random AI art every day

Jess Farber
11 min readJan 16, 2023
A picture frame displaying a small squirrel

TLDR

I wrote a program and put together a little raspberry pi unit to automatically request and display art generated by an AI provider (at present DALLE and Stable Diffusion) in an E-Paper frame. The final build turns on for a minute or two every day, requests a prompt, displays the image on the screen and shuts down. It runs on battery and does not need to be plugged in until it needs to be recharged. There is no soldering required. It cost me $300.16 AUD excluding the frame.

You can do it yourself by putting together the following ingredients:

  • Raspberry pi 4 (It could also work on earlier models but I haven’t tested this)
  • An E-Paper screen (like this one)
  • A matching picture frame (You could just grab one from IKEA or get it professionally done or anything in between)
  • Optional but recommended: PiJuice HAT
  • Some credit on OpenAI and/or Stable Diffusion API
  • Connect everything and then follow these instructions to install the code.

The above is probably all you really need to set this up yourself as I tried to make the install script as painless as possible, however, the rest of this article will go into a bit more detail on the process of how I put things together and built the program throughout the project.

Acknowledgements

Inspiration for this project based on Tom Whitwell’s SlowMovie and the very helpful write-up on setting up E-Paper to work with a Raspberry Pi unit. I also liberally reused a lot of the install.sh script from this project because of the similarities in requirements and because it’s pretty good. I would also like to acknowledge robweber who not only created omni-epd which I implemented so that this can work dynamically with many displays, but also provided me with a lot of good code examples that I referred back to often to try to ensure I was following best practises.

Introduction

In lockdownish days from 2020 I was looking for a project to pass the time. I googled for a raspberry pi project and found SlowMovie. I ordered myself a Raspberry Pi 4 and a Waveshare E-Paper Display (EPD), the same one used in SlowMovie to make things easier on me. Unfortunately, due to how well documented and scripted SlowMovie was, less than 2 hours passed and it was ready and working. A short time later I threw it in an IKEA frame and was done. I really loved my little slow movie player, but it didn’t really scratch my itch of a full-blown project. It sat next to the TV for a few months, slowly playing some of my favourite movies.

In 2021 I learned that people were using AI to generate weird and wonderful images. Development and maturity in AI art applications improved at a meteoric pace over the next year. It wasn’t too long until Stable Diffusion and DALLE released APIs producing good-looking image generations from text. Already having a system that was currently displaying its own form of artwork, it seemed like a fun idea to see if I could grab a daily AI-generated image to show on my frame.

Starting Out

Out of the gate I already had my pi connected to a black and white EPD from SlowMovie, and it didn’t take long to mess around with waveshare’s example code to have it displaying my own images. Throwing everything together was made even easier with omni-epd. Implementing this wrapper for the EPD meant that the app should work for any EPD listed here (the mock EPD item also made it far easier to test in different environments).

A black and white E-Paper Display showing ‘A Cool Bird Wearing Glasses’ in the style of Lichtenstein
Well, it works.

While I started running this through a black and white EPD, due to the interesting images I had been getting, I decided to splurge on a new 7-colour EPD from waveshare, which looks a lot prettier and the colour images pop really well. The only drawback is a long update time compared with the black and white displays (about 30 seconds). This manifests in ugly and annoying flashing, which is unpleasant and distracting for something that is on display. This isn’t really much of a problem in my case though as I’m planning on just requesting new art every day, I can set it to do so after hours. I recommend this display, as far as I can tell it’s currently the biggest EPD you can get of this colour depth that is supported by omni-epd. That being said, you should be able to use any EPD listed here with this application and it should work.

Connecting this to the pi wasn’t quite as easy as the 7.5 inch, it came with a lot of separate cables to plug into the correct pins on the pi. The unit comes with instructions on where to plug the cables, and I used this guide to double check I was plugging into the correct pins, as voltage flows through some of these pins and I didn’t want to fry my brand-new screen.

A colour E-Paper Display, plugged into a Raspberry Pi, showing ‘Sydney Opera House’ in the style of Lichtenstein
More interesting than black and white

Building A Prompt

I wanted to make sure I could define the kind of prompts I wanted, but I didn’t want to type them all verbatim. That isn’t particularly surprising or interesting. While I’ve left the functionality to do that, my preferred method to run is with a random <subject> and <artist> pair. For example, “Dubstep by Henri Matisse”. We can also configure prescript and postscript, such as the weird flavour statements loved by all AI art fans like “trending on artstation” or “ultra HD, 4k” that is supposed to create higher-quality artwork.

A colour E-Paper Display, plugged into a Raspberry Pi, showing ‘Dubstep’ in the style of Henri Matisse
Dubstep. By Henri Matisse.

To complicate it a bit more I also added a bit of markup that allows randomising words in the prompts, so we can have really complex strings with wildcards replaced every single time. This allows us to throw more adjectives and complex prompts together, for example “A Sad Magpie With A Tea Cup” instead of just “A Magpie”. One thing I will note is as the prompts become more complex or abstract, the AIs tend to get confused more often. But it’s still fun to see them try.

An AI-generated image of ‘A Sad Magpie With A Tea Cup’
A Sad Magpie With A Tea Cup

For future work I might look into implementing a dictionary where we could replace <nouns> or <verbs> in a ‘mad-libs’ type way to create interesting content.

Requesting Images

DALLE and Stable Diffusion both created API wrappers in python which were not particularly hard to implement. With pycasso we can easily set our API key during the setup script, and update any time we require.

I had an immense amount of difficulty reliably getting keychain to work on raspberry pi, so as much as I am loathe to do so, the API keys are just stored in a plaintext file on the pi. But for a relatively low value key on your home network that shouldn’t be on more than 5 minutes a day, I think this level of risk is alright.

DALLE had a complication where it only can return images to us of the size 256x256, 512x512 or 1024x1024. We can crop the image to fit the screen, however AI images often tend to result in an overly zoomed-in image, and cropping just exacerbates this issue. An alternative solution was to reupload the image from DALLE and ask it to infill the edges of the image into a bigger size. Not only does this mean we don’t need to crop the image, it offers an opportunity to scale the image down a little and add more natural space. Note that this does count as additional request which will charge the user again for API usage.

The generic costs in requesting images from Stable Diffusion and DALLE for my 600×448 pixel screen were:

  • DALLE Image — $0.01 USD
  • DALLE Upscale — $0.02 USD
  • Stable Diffusion Image — $0.01 USD

Requesting one image a day is pretty cheap and even after months of testing and running multiple requests a day, I haven’t even hit $5 USD total yet.

Saving Power

My favourite thing about e-paper is that it doesn’t need to be powered to maintain an image. If the only work the pi needs to do is to retrieve an image and display it, realistically it should only be powered on for a maximum of 5 minutes a day, ideally shorter. PiJuice turned out to be the answer to a few things I was hoping to implement — battery power and automatic wakeup/shutdown.

The PiJuice unit plugs pretty snugly and securely onto the board, with no soldering required. PiJuice also keeps most of the GPIO pins exposed apart from a few it requires to regulate the power, meaning we can still plug our HAT onto the top of it, and it will still display images just like before.

After a quick configuration, we have a battery-powered unit that doesn’t need to be plugged in to power except to recharge. It powers up at a predefined recurring time, and then turns itself off again. No cables, someone can hang it on the wall if they like. It has 3 switches on it and the first switch by default boots the pi unit, which is perfect for cycling the image ad-hoc. The PiJuice class in python has a lot of features which I’m still exploring. We currently use the battery level information to draw a little square in the corner of the screen when the battery is low.

A command line interface displaying ‘PiJuice CLI’ and its Wakeup Alarm settings
Configuring wakeup timer in pijuice_cli

I think this results in a nice mobility that allows far nicer set-and-forget configuration, as well as doing away with ugly cables and LEDs coming out of the device. I threw a flag into the program to check if PiJuice is plugged in to power, and if so, it does not shut down. That way we can still administer it if we require.

Framing

After the whole system had been working well for a while, I went into a local framer and got one built professionally to replace my IKEA frame situation. I chose a thick frame to house the pi with its PiJuice in, and the framers did a really good job leaving the PiJuice recharge port accessible, as well as the macro buttons. The frame can be hung up on the wall but for now I’ve just got it sitting in a nice little spot near the TV, mostly due to hesitance to throw a new hook up on the wall.

The back of a picture frame, with a Raspberry Pi inserted into a custom-cut hole
A cosy new home

Overall, I’m happy I got it framed, it really completes the look and, in a way, tied everything together at the end of this project.

A picture frame displaying ‘A Happy Cowboy’ sitting on a shelf next to an average bowl of fruit
Yee-ha. Lookin’ good, cowboy.

AI Art And Respect To Artists

There’s a lot of discussion ongoing about AI art and its impact on the art community. I can’t in good conscience publish this article and application without acknowledging this. AI art has come a long way in a very short time and is shaking up creative communities. Many artists have been struggling even before AI came along, and it would be understandably devastating to find people online using your style or artworks to generate images without any compensation or even attribution.

I’ve created this application and set up because it’s fun and interesting. My intent is not to steal the work of other artists or harm people’s careers. My thoughts for anyone reading and using this application is that if you like a particular style, that comes from real artists and you might enjoy owning something that they have created. Or you might consider donating to an artist that you like the style of. Remember, to use this application you’ve probably already spent a bit of money on the hardware and API access, just a little donation will still go a long way to ensuring we protect artists.

Basically, please remember there are real artists behind these artificial models and they deserve our respect. If you particularly like a certain style or artist, consider supporting them.

Summary And Next Steps

Overall, this cost $300.16 AUD excluding the frame, and kept me out of trouble for quite a while. The frame itself is probably the most contentious of the costs, costing almost as much as the rest of the components combined, but considering the amount of time I plunged into this thing it felt somewhat deserved.

Shopping list

  • Rapberry Pi 4 — $66.92 AUD
  • 16GB SD card — $18.70 AUD
  • PiJuice HAT — $109.95 AUD
  • 5.65inch 7-Color E-Paper E-Ink Display Module — $104.59 AUD
  • Professional Framing — $279.00 AUD
A picture frame next to a banana and a measuring tape
Banana for scale

I have a lot of features I’d like to implement, and plan to roll them out when I have time. I’ve just been doing this in my spare time and for better or worse, lockdowns don’t look to be in my near future. Mostly I’d like to add quality-of-life features, including a webui to make things easier to configure, set up and manage. I’m also interested in squashing bugs so even though I can’t guarantee support, feel free to create an issue here if you experience problems or want to request features. I’m not a professional coder but I will do my best given my ability and spare time to make sure pycasso works well for whoever wants to use it.

FAQS

Not many people have asked me any questions about this project yet but I’ll try and pre-empt some.

Why not run an AI art algorithm on the pi itself? Wouldn’t that remove the ongoing cost and requirement to contact the internet?

Crunching models to create AI art requires a lot of graphics memory. Any art you could generate on a pi with current algorithms would be tiny, and would not look particularly good. This may change, but at the moment it’s not really possible. I am considering, however, the possibility of having an option to poll a local web server like one available here (https://github.com/AUTOMATIC1111/stable-diffusion-webui). An interesting side note is that you could train your own model for this, allowing you to have the frame show pictures of yourself, in different styles! (Edit 02/2023: This has been implemented)

Have you thought about using ‘Partial Update’ to avoid the annoying flashing when updating the screen?

Yes, however as far as I understand, the flashing on E-Paper screens is required for safety due to the way they operate. The ink is moved around by charging the cells positively or negatively, and if you apply the same charge too many times, you could wind up with the EPD equivalent of a ‘dead pixel’. While I think we could get away with some partial updating, for safety’s sake I’ve not looked into implementing anything like that yet.

How long does the battery last?

I might come back to this question later as I haven’t actually fully run it down on the most recent version of the program, every time I made an update to the code I plugged the device back in to power to administer it. As far as I can tell it should work once a day for a month on default settings.

--

--