Photograph To Painting


I am Pushpak.

I developed a code that converts any photograph to a painting-like picture.

I came across snapchat filters that converts images to watercolor painted images and I wanted to create a similar kind of filter using python. After some research, I came across few articles that explains how it can be implemented. So I created a process and the process consists of 4 major parts:

  • Reading the image
  • Creating edge mask
  • Reducing the color palette
  • Combining edge mask and new color palette

Sample Generated Images

Sample Input Images

Load Images

img = cv2.imread(“C:\Computational Photography\Final\Obama.jpg”)


I used openCV imread function to read images and numpy is mostly used in this project.

Genrating edge mask

edges = cv2.Canny(img, 100, 200)

cv2.imshow(”, edges)


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 5)


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

gray_1 = cv2.medianBlur(gray, 5)

edges = cv2.adaptiveThreshold(gray_1, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 5)

I applied cv2.adaptiveThreshold() function. Parameters for this function are defined as:

  • max value which will be set to 255
  • cv2.ADAPTIVE_THRESH_MEAN_C: a threshold value is the mean of the neighborhood area.
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C: a threshold value is the weighted sum of neighborhood values where weights are a gaussian window.
  • Block Size – It determents the size of the neighborhood area.
  • C – It is just a constant which is subtracted from the calculated mean (or the weighted mean).
Commonly, a cartoon effect emphasizes the thickness of the edge in an image. By the use of a median filter, I was able to define edges more precisely 

Reducing the color pelatte

def color_quantization(img, k):
  data = np.float32(img).reshape((-1, 3))
  criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)
  ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
  center = np.uint8(center)
  result = center[label.flatten()]
  result = result.reshape(img.shape)
  return result

I created a color_quantization() function. Parameters for this function are defined as:

  • img is the original image passed
  • k is the value of total number of colors which we are going to use

We will perform color quantization by using the K-means clustering algorithm for displaying output with a limited number of colors.

Combining edge mask and new color palette

img = color_quantization(img, 8)
blurred = cv2.bilateralFilter(img, d=7, sigmaColor=200,sigmaSpace=200)
cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)
cv2.imshow(”, cartoon)

bilateralFilter is used to reduce the noise which was left after quantization.

In the end, the bitwise_and() function is used to combine the edge mask and the new color palette.



Contact Me