Recently, I’ve been intrigued by the art of drip painting. You’ve probably come across Jackson Pollock’s beautiful canvases and as a fun experiment I tried to recreate them digitally with some Computer Vision. For this particular example, I used data from a DIY wind-sock to drive the pattern. I think its quite interesting to look at the resulting images since they are each unique and reflect the particular weather and location conditions from which they were created.
Getting started
To create a windsock, I taped a circle cut out of some red paper to a length of wool. The paper does need to be heavyweight, or it flutters about quite uselessly and fails to move in a meaningful way. The wool was then tied to a long stick and held at an arms length and the red marker filmed from above.
The reason for using a red marker is because a very intense red isn’t commonly present in many natural scenes – so its quite easy to extract it out of an image. I filmed the video in my terrace and since the tile was a grey tone, it wasn’t too much trouble isolating the red.
Processing the video
Extracting the red marker
First I converted the frame to HSV colorspace. This makes it easy to locate the red tones irrespective of lighting conditions.
Then using cv2.inRange() I create a mask . If youd like to learn more about this- I highly recommend reading this blog post
frame1 = cv2.resize(frame1, (568,320)) #resize the frame to see it better
out=np.full_like(frame1,[0,0,0])
hsv = cv2.cvtColor(frame1,cv2.COLOR_BGR2HSV)
lower_red = np.array([0,120,70]) #declare an upper and lower bound for the hue red
upper_red = np.array([10,255,255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
lower_red = np.array([170,120,70]) # the values for red are present next to blue as well as next to yellow
upper_red = np.array([180,255,255])
mask2 = cv2.inRange(hsv,lower_red,upper_red)
mask1 = mask1+mask2
res = cv2.bitwise_and(frame1,frame1, mask= mask1)
Calculating the Dense Optical Flow
Im using cv2.calcOpticalFlowFarneback estimate the dense pixel motion of my marker. This returns the magnitude as well as the direction of movement of each pixel.
Setting up variables
Coordinates
Create a contour around the processed marker and calculate its center of mass. This serves as a coordinate for setting down a circle to look like a drop of paint.
I append all the coordinates to a list and handle the painting later.
Direction
Create an ROI around the marker and average the hues within this box to get an estimate of the direction. Similar to the process above, I append this to a list
Magnitude
Calculate the average lightness within the ROI to get an estimate of the magnitude and append to a list
c = max(contours, key = cv2.contourArea)
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
x,y,w,h = cv2.boundingRect(c)
roi=hsv[y:y+h,x:x+w ]
roi2=out[y:y+h,x:x+w ]
roi2= cv2.cvtColor(roi2,cv2.COLOR_BGR2HSV)
vals=np.reshape(roi,(-1,3))
vals2=np.reshape(roi2,(-1,3))
flat_vals=np.average(vals,axis=0)
flat_vals2=np.average(vals2,axis=0)
line=int(flat_vals[2]/35)+1
hues_detected=flat_vals[0]
hue_list.append(hues_detected)
coords.append([cX,cY])
movements.append(flat_vals[2])
Painting
Calculating abrupt changes in direction
After watching a few drip painting videos online, I noticed that a change in direction would be pronounced using a larger splatter. So I plotted the list of hues to take a better look at the changes in direction and found the peaks using scipy.signal.find_peaks to calculate the points at which the direction changes.
Painting!
Once you find get the information from the video, the possibilities are endless. For this particular example, I set a matrix to be white by filling it with [255,255,255] and created a black circle on top for each frame of my original video. I varied the size of the circles according to the magnitude variable and added some lines between a couple of the smaller circles for it to resemble a drip painting. In the future, I look forward to experimenting with more colors and effects to create interesting pictures.
Get the code
To try out the code,you can find a link to the jupyter notebook here. I hope you found this article interesting and I look forward to seeing your creations.