If ( ) Then {Paint}

a machine to create canvas paintings of your favorite digital images

Similar projects worth following
A cnc painting system that artists, crafters, and makers can use to create canvas paintings of their favorite digital images cheaper and faster than ever before.

Simply upload an image, define the painting parameters, load the raw materials, and watch the machine create your custom painting.

The Problem

We can create and share custom digital images at almost no cost but recreating our favorite digital images in paint on canvas is an expensive service that most cannot afford.

In today's world, if you want a custom canvas painting of a digital image you really only have two options. Either roll up your sleeves and spend the next couple of years learning how to bring your ideas to life on canvas or commission an experienced canvas painter to do it for you. Regardless of which route you go down, it's not going to be cheap. Say you want three or four custom paintings for your living room or office - you may end up paying more for the paintings on the wall than you did for all the furniture in the room!

It's not the raw materials that make canvas paintings expensive. It's the time and dedication required to master hand-eye coordination, brush technique, and paint color mixing. But even if you decide to pay the high cost of mastery, there are still no shortcuts to creating canvas paintings. Good paintings simply take hours to create. 

The Solution

A cnc painting system that artists, crafters, and makers can use to create canvas paintings of their favorite digital images cheaper and faster than ever before.

Weigh the high cost of custom canvas paintings against the decreasing costs of cnc machine components and software development and you will find that cnc painting systems can pay for themselves and start adding value in record time. 

Ultimately, the If Then Paint cnc painting system adds value by automating the technical challenges that make custom paintings so expensive and time consuming. It can place paint on canvas with millimeters of precision, be programmed to perform any number of advanced brush stroke techniques, and mix hundreds of paint colors on demand. On top of that, it will perform all of these tasks through day and night without interruption. 

Operating the machine doesn't take years of practice and dedication either. Simply upload an image, define the painting parameters, load the raw materials, and watch the machine create your custom painting.

The Potential

  • A canvas painting productivity tool that artists can use to either create originals or replicate their best sellers faster than ever before.
  • A tool for crafters that reduces the amount of time and practiced skill it takes to add personalized painted embellishments to decorations and paper crafts. 
  • An flexible system architecture that gives makers and hackers the ability to develop their own digital image to paint stroke g-code algorithms and make mechanical enhancements to the machine with ease.
  • A platform that painters around the world can use to share techniques and recreate each others work.
  • A sign making tool for small businesses.
  • A canvas painting learning tool for young artists.
  • A platform for new canvas painting innovations.

The Team

John Opsahl is a hacker and creative. He works as a mechanical design engineer for a lithium battery manufacturer. After hours he develops new cnc art machine technologies and designs laser cut products for his Etsy shop. All of his projects address the challenge of making new technologies and products available to a larger audience.

He is currently looking for a business development...

Read more »


3D model of the If Then Paint cnc machine

step - 21.67 MB - 08/02/2019 at 02:54


  • limit switches and homing sequence

    John Opsahl09/07/2019 at 17:10 0 comments

    I was having some issues last weekend removing noise on the paint management system axis limit switches. The consequence of noise being that even when none of the limit switches were pressed, grbl would stop the machine an indicate a hard limit switch alarm. This seems to be a fairly common issue among grbl users when wiring the limit switch signal wires directly to the Arduino. The grbl wiki recommends using an RC circuit or better yet opto isolation - I tried the RC circuit method with the recommended resistance and capacitance values but still got false hard limit switch alarm trips. After a few hours of troubleshooting, I discovered that by routing the limit switch signal wires away from the stepper motors and stepper motor power wiring the false alarm trips would no longer occur. The paint management system has operated well since rerouting the signal wires, but I am skeptical whether the machine will be able to operate without false alarm trips for durations up to several hours without a robust signal filter or isolation solution. Though at the moment, I am grateful to have found a simple solution.

    After resolving the noise issue on the limit switch signal wires, I was able to set the homing sequence and perform the homing operation on both machines. Previously I had issues with getting the grbl homing operation to work. Using the "show verbose output" feature of the Universal Gcode Sender open source application (, I discovered that the unused axis limit switch pins where being treated as "activated". Connecting all the unused limit switch pins to ground solved the issue and the homing operation now works great. 

    The six axis brush control cnc machine homes to X-, Y-, and Z+. The homing sequence is Z+ then X- and Y-.

    The paint management system homes to X-, Y+, Z-, and B-. The homing sequence is X- and Y+, Z-, then B-.

    During the process of developing the homing sequence, I realized that some of the dimensional control parameter datums needed adjustment. For example, on the paint management system I originally planned on homing to Y- but at that end of the machine there isn't any room to home the Z axis (the water dish is in the way). So after established the appropriate homing sequence for each machine, I spent some time updating the dimensional control parameter values that tell the machine where in the workspace objects (i.e. water dish, paint palette, canvas, etc.) are located. All of the new values are captured in the If Then Paint Image2Gcode code on GitHub (

  • open source code

    John Opsahl08/27/2019 at 04:23 0 comments

    All code for the If Then Paint project has been released under LGPL-3.0 on GitHub. 

    Link to the repository:

    I will continue to update the code and documentation in the GitHub repository as this project develops.

  • bitmap image to paint stroke g-code - part 4

    John Opsahl08/23/2019 at 19:35 0 comments

    At this point in image to g-code process we know what lines to paint and what tool and paint color to paint them with. What we haven't accounted for are all the dynamics that come into play during the cnc painting process. How far can the brush paint on canvas before it needs to go back for more paint, how often does the brush need to cleaned so paint doesn't dry and build up on the bristles, what movement is required to load the brush with paint, how much paint is required to create the painting, is there enough room on the palette to fit all the paint needed to create the painting, etc. Solving these challenges requires more of a bookkeeping mindset than a mathematical one.

    The first step of addressing these dynamics is to understand how much paint is required for each layer of the painting. Only three values are needed to arrive at the layer paint quantity estimate - the total distance the paint brush travels on the canvas during the layer, the maximum distance the paint brush can travel on the canvas before it needs to be loaded with more paint, and the quantity of paint required to load the brush. The latter two are determined through experimentation.  

    The next step after determining how much paint is required is to map out where on palette to dispense the paint both so the paint management system knows where to dispense the paint and the six axis brush cnc machine knows where on the palette to go to load the brush with more paint. I have chosen the approach of dispensing beads of paint in rows that run the long dimension of the palette. If the length of bead that needs to be dispensed is longer than the length of the palette, the remaining bead length will be dispensed on the next bead row.

    After the palette paint map is finished, writing the machine instruction g-code is just a matter of following the correct sequence of operations: 1) get the tool from its dock, 2) wet the brush, 3) load the brush with paint color 1, 4) paint on the canvas, 5) load the brush with paint paint color 1, ... 20) clean the brush, 21) load the brush with paint color 2, ... Each operation having unique movements and control parameters. Some that can be calculated and others that have to be determined experimentally. This is where the dimensional control parameters that I have described in a previous project log come into play.

    Since many of the control parameters are experimental, the g-code writing script I developed writes all the relevant object control parameters at the appropriate location in the g-code file. I suppose as this project becomes more mature, these parameters may become standardized through experimentation and no longer need to be logged in the g-code file. Like I said; it's mostly bookkeeping. 

    This concludes the bitmap image to paint stroke g-code project log series. I am always happy to answer questions or provide a higher level of detail upon request. Please post any questions and comments to the main project page. 

  • bitmap image to paint stroke g-code - part 3

    John Opsahl08/23/2019 at 16:53 0 comments

    Defining layers is the next step after generating stroke lines from the image. Layers are a high level structure that associate the stroke lines with an available paint color and tool profile. Layers in this context can be thought about in the same way that you would think about layers in an image manipulation program like Adobe Photoshop or GIMP. The layers beneath will be painted first and the layers on top can overlap the layers beneath. 

    I usually follow one of two thought processes when assigning a paint color to a layer: 1) I let the software automatically select the paint color that is stocked on the machine and is closest to the rgb value of the image color of the stroke lines, 2) If I want to abstract the colors of the painting, I manually select any color that is stocked on the machine.

    The tool profile defines what tool is to be used and in what way. I can think of at least ten ways to orient a flat brush on a canvas to create different brush stroke effects. A tool profile defines just one of those ways.

    After layers have been defined, we can create a preview image of the painting. The painting preview image below is a continuation of the example from part 1 of this project log series. It is black instead of dark green because I had the software automatically assign the stocked paint color that was the closest match to the image color. Apparently, the dark green was closer to black than the green that is also stocked. 

    If after viewing the painting preview you don't like what you see, it's easy enough to regenerate stroke lines using different input parameters, assign a different paint color or tool profile, and create another painting preview image. 

    Creating the painting preview image concludes the image processing component of the image to g-code process. The steps that follow are specific to developing the If Then Paint machine g-code machine movement instructions from the layer structures.  

  • bitmap image to paint stroke g-code - part 2

    John Opsahl08/23/2019 at 13:31 0 comments

    This project log is going to focus on the line scan algorithm parameters used to generate paint strokes from a bitmap image. I described the longest line selection component of the algorithm in a previous project log ( so I will not touch on it here. 

    I like to think that the If Then Paint line scan algorithm is just the beginning of what is possible. There are other unique approaches to generating paint stroke lines from bitmap images that have not been explored yet. Each possible of creating unique painterly effects. Wouldn't it be great if we had a cnc painting machine platform to test out new algorithms and have multiple algorithms available in a single software package? -> Well, welcome to the If Then Paint project.

    At a high level, the If Then Paint line scan algorithm works by scanning the paint brush profile size across the image at different angles, looking at whether each paint brush profile location has a high enough percentage of pixels of the scan color to be considered a valid location, then connecting adjacent valid brush profile locations into valid stroke lines. It is a computationally heavy, brute force method that has worked well so far to generate paint strokes from any bitmap image. 

    The following line scan algorithm input parameters can be adjusted to create different painterly effects:

    • Scan Angle. The scan angle is the angle (relative to the horizontal) at which the algorithm scans the brush profile size across the image. Specifying the number of scan angles to use is a balance between ensuring that the stroke lines are scanned at enough angles to follow the contours of the image and the duration it takes to perform the line scan. The number of scan angles is the most influential factor on how long it takes to perform the line scan algorithm. A low scan angle count will give the painting a more grid or cross hatch look. A high scan angle count will make the paint strokes look more organic and flowy.
    • Profile Width. The profile width is the width of the stroke profile that gets scanned across the image. A larger profile width is representative of a larger physical brush width and vise versa. Larger brush profiles are good for covering large single color areas. Smaller profile widths will capture finer image details.
    • Profile Length. The profile length is the forward increment that the stroke profile advances along the scan angle. A smaller profile length will result in better coverage at the image color boundaries but will also increase the run time of the algorithm. 
    • Color Match Threshold. The color match threshold is a percentage value used to validate or invalidate a profile location. If the percentage of pixels within the profile location that match the scan color is greater than or equal to the color match threshold, the profile location is considered valid. A smaller color match threshold will make the stroke lines of a line scan more dominant at the color boundaries. Too high of a color match threshold can make a no man's land between color boundaries; where no stroke profile has a high enough percentage of pixel color matches to be valid. 
    • Scan Line Overlap. The scan line offset overlap is the overlap between two adjacent and parallel stroke profile scan lines as a percentage of profile width. It translates directly to physical paint stroke overlap. A scan line overlap of zero will result in no overlap between parallel strokes. A larger scan line overlap decreases the distance between scan lines which increase the number of scan lines required to cover the image and increases the algorithm run time.
    • Minimum Line Length. The minimum line length parameter controls the minimum allowable stroke line length. I use a small minimum line length that is just larger than zero when I want to reduce the number of "dot" strokes....
    Read more »

  • bitmap image to paint stroke g-code - part 1

    John Opsahl08/22/2019 at 21:26 0 comments

    Four days, seven coffee shops, and 750 lines of code later and I am getting very close to finalizing the Python project that can generate the If Then Paint prototype machine g-code from bitmap images. It's been a little over two years since I first starting developing the code. I figure it's time to finally describe the process from image to g-code and detour to some of my favorite challenges that I encountered along the way. 

    It starts with an bitmap image. In this case, it is a picture of a tree in a meadow that my wife took on our last vacation.

    The bitmap image then gets sized to match the aspect ratio of the physical canvas and resolution of the digital canvas (see sized image below). If we didn't want to lose the proportions of the original image, we can just open the original image in an image manipulation program, cut out the desired section of the image with the same aspect ratio as the physical canvas, save the section as a new image, treat the new section image as a new original image, and perform the sizing process. I have chosen not to keep the original image proportions to make it easier to visualize what the resizing process is doing. The image is sized to the resolution of the digital canvas because a spatial reference between pixels and millimeters is needed. The If Then Paint prototype uses a 768x1024 digital canvas resolution for a 120x160mm physical canvas (i.e. 6.4 pixels per mm).

    The next task is to simplify the image to only a few colors using color quantization. The image below is reduced to just five colors. The primary reason for reducing the number of colors is to reduce the number of paint colors that need to be mixed to create the image. The original bitmap image might have hundreds of colors. Mixing hundreds of colors will take a long time and the final painting might actually look better with fewer colors.

    After color quantization, we can start to apply the secret sauce of this image to g-code recipe - the algorithm that generates paint stroke options from the bitmap image. With a simple horizontal and vertical scan of the dark green color, we get the following possible paint strokes (shown in purple for contrast but also for fun). The next project log will dive deeper into the details of the algorithm.

  • machine control dimensions

    John Opsahl08/16/2019 at 04:01 0 comments

    In contrast to 3D printers and cnc mills that only have one or two objects to interact with within the workspace (e.g. bed and stock material), the cnc painting machine interacts with multiple objects like the canvas, towel, water, and paint palette. The tables that follow detail the object dimensional information needed to develop the cnc painting machine control instructions (gcode) for the If Then Paint proof of concept prototype. Most of these dimensions are fixed, but some may need to adjusted as the gcode is developed and tested (z_water_dip for example).

    You will see paint palette object dimensions for both the six axis brush machine and paint management machine because both interact with the paint palette but in their own coordinate systems.

    Six axis brush machine control dimensions (tool docks, brush cleaning water, brush wiping towel, canvas, and paint palette objects):


    Paint management system machine control dimensions (paint palette, dispenser, syringe water, and paint objects): 


  • origin and axis orientations

    John Opsahl08/14/2019 at 17:00 0 comments

    I developed the following graphics to help clarify the location of the origin and orientation of system motor axes. My hope is that these graphics will make it much easier to discuss motion control strategies for the If Then Paint cnc painting machine moving forward. 

    The origin of the six axis cnc brush control machine is located at the bottom left corner of the canvas. The paint management system does not have an absolute origin. Instead, it has a home position at the -x, -y, and -z limits of the paint management system axes.  

    The arrows point in the positive direction of the depicted axis. All axes have the capability to move in both directions.

    The x-axis positive direction is into the paint carousel. When developing the machine movements, it's generally easier to think about machine movements relative to the "tool" (i.e. paint dispenser in this case). Since the bed (i.e. palette) is moving and the tool is stationary, a bed positive movement towards the tool can be thought of instead as a tool positive movement across the bed. 

  • bitmap image to paint stroke examples

    John Opsahl08/07/2019 at 03:35 0 comments

    One of my goals this week was to explore what bitmap image to paint stroke conversions are possible with very simple conversion parameters. In the three image conversion examples below, the original reference image is on the left and paint stroke preview image is on the right. None of the images are a result of being physically painted by a cnc painting machine. The preview images are just approximations of what a final painted image might look like. The longest line algorithm (described in a previous project post) was used to generate paint strokes from the reference image. The generated paint strokes were plotted in their respective colors to construct the preview images. A single round brush size and no more than six paint colors were used to construct each preview image. Even with these simple parameters, the paintings are still fun to look at and given past experience, they will probably look much smoother as actual paintings. The rough and jagged borders between colors shown in the preview images are less striking once physically painted. These conversions get me excited about what might be possible with more complex parameters.

    Another thing I really enjoy about these conversions is that even though I know what the reference image looks like and the painting parameters that the algorithm is using, the result can still be surprising. For example, it's always interesting to me how the algorithm removes detail from the original image, but in some way the message and feeling of the image is not lost. Like the fine details are not what really mattered. 

    This also motivates me to fully develop the paint management system. Without the paint mixing component of the paint management system, I currently have to manually mix paints until the correct color is achieved. Once fully developed, I won't have to mix paints anymore and painting with more than six colors should no longer be much of a challenge.

  • fabrication files posted

    John Opsahl08/01/2019 at 02:03 0 comments

    All fabrication files needed to build the cnc painting machine have been released to the GitHub repository:

    The fabrication files are listed separately for the two cnc subsystems - the six axis cnc and paint management system. Six laser cut 12x24in sheets of 0.175in baltic birch plywood and two 3d printed parts are required for the six axis cnc machine. Ten laser cut 12x24in sheets of 0.175in baltic birch plywood and one 3d printed part are required for the paint management machine. The bills of material include quantities and descriptions of all the purchased components.

    A .step solid model file of the entire machine is included for dimensional reference as well.

View all 20 project logs

Enjoy this project?



Tom Nardi wrote 08/03/2019 at 04:58 point

Love the use of keyless drill chucks to hold the brushes, brilliant reuse of a common part.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates