Abstract Mirror - html elements and video in p5.js

Unfortunately my laptop has seen better days, so I was limited to what I could really do with this sketch. Fortunately, the hardware limitations made me consider a simple project that would still have a profound esthetic. I created something with a very Abstract-Expressionist feel to it, using a webcam to explore color instead of imagery. Basically, it draws vertical bars on the screen, each bar being the average RGB values of all of the pixels it covers. To combat hardware limitations further, and to practice creating HTML elements, I put in some user controls to optimize the graphics in runtime. The sketch accomplishes the following:

  • Demonstrates the use of video capture and HTML elements.
  • Uses HTML elements as a means of graphics optimization and user control over the display.
  • Non-intrusive user interface.
  • Demonstrates further understanding of pixel array.


  • This program is literally version 3 of 5, where versions 1,2,4 and 5 either failed or proved to be too demanding on hardware. 1 and 2 essentially tried to reinvent the wheel (manually coding color tracking, something the OpenCV library already does). 4 attempted to use a Sobel Edge Detection algorithm to make outlines around things, which was VERY hardware intense, and something Tracking.js already does. 5 tried to do what 3 does, except with mp4 files. For some hair-pulling reason, it won't read the video correctly, so I abandoned it and went back to 3.
  • The main algorithm was pretty straight-forward. On each column of pixels, sum all the red, green and blue componentvalues (three different sums for the three components). Before going to the next column, divide the sums by the number of pixels in the column to get the average RGB components. Save this color to an array of fill colors (this was changed for optimization, which I'll address later). Do this for all columns in the webcam feed. Once complete, print rectangle primitives, one for each column, filled with the corresponding color from the array of fill colors. The width of each rectangle is windowWidth/capture.width.
  • Despite the simple operation, the frame rate was very, very slow. Because no one will really notice details missing, I opted for skipping columns. I also only added half of the pixels in a column to get the color averages. These two factors greatly improved the frame rate.
  • The pixel skipping was purely arbitrary, which made my CS conscience squirm a bit. Instead I wanted to find the optimal amount of skipping using some calculus. However... I decided instead to give the user control over how many pixels are skipped. This was MUCH easier to program, gave me some practice programming HTML elements and potentially produced more creative results.
  • With this new game-plan in motion, I decided to add the Mirror and Invert options. Mirror draws the rectangles in reverse order, making the output mirror the input. Invert simply inverts the colors (255 - RGB component). Each option is trigger by their respective booleans, which are toggled by HTML check boxes.
  • Two HTML sliders control the pixel skipping. The slider values tell the for loops in the color processing function the number of pixels in each column (even spacing between each) and the number of columns to look at.
  • Having these options plastered on the screen took away from work. Instead I created a little function that hides the options menu and draws it to the screen when told to do so.
  • This options-menu-hiding function seems to create a tiny glitch that I can't seem to reproduce dependably. Sometimes when the menu is closed, the settings do not persist. E.g. I check the invert colors box, the colors invert. Then I close the menu and the colors go back to normal.
  • Lastly, I realized my color processing program created some redundancy. Processing iterates until it exhausts its list of pixels, saving each averaged color to an array. In the draw function, this array is accessed in another loop. This forces the program to perform an additional long iteration. To optiize, I included the pixel processing into the draw loop, so that the rectangles access the color value as its created and not from an array.