Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
4.4 KiB

  1. Let's jump right into the fun and start making pixel art with Open CV.
  2. Before you read this article, consider checkout out these articles:
  3. - [Shallow Dive into Open CV](https://jrtechs.net/open-source/shallow-dive-into-open-cv)
  4. - [Image Clustering with K-means](https://jrtechs.net/data-science/image-clustering-with-k-means)
  5. Like most CV projects, we need to start by importing some libraries and loading an image.
  6. ```python
  7. # Open cv library
  8. import cv2
  9. # matplotlib for displaying the images
  10. from matplotlib import pyplot as plt
  11. img = cv2.imread('dolphin.jpg')
  12. ```
  13. I like to define scripts to print images nicely in a Jupyter notebook.
  14. ```python
  15. def printI(img):
  16. rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  17. plt.imshow(rgb)
  18. def printI2(i1, i2):
  19. fig = plt.figure()
  20. ax1 = fig.add_subplot(1,2,1)
  21. ax1.imshow(cv2.cvtColor(i1, cv2.COLOR_BGR2RGB))
  22. ax2 = fig.add_subplot(1,2,2)
  23. ax2.imshow(cv2.cvtColor(i2, cv2.COLOR_BGR2RGB))
  24. printI(img)
  25. ```
  26. ![original image](media/pixel/output_2_0.png)
  27. To pixelate an image, we can use the open cv resize function.
  28. To make the image viewable, after we shrink the picture, we resize it again to be the size of the original image.
  29. ```python
  30. def pixelate(img, w, h):
  31. height, width = img.shape[:2]
  32. # Resize input to "pixelated" size
  33. temp = cv2.resize(img, (w, h), interpolation=cv2.INTER_LINEAR)
  34. # Initialize output image
  35. return cv2.resize(temp, (width, height), interpolation=cv2.INTER_NEAREST)
  36. img16 = pixelate(img, 16, 16)
  37. printI2(img, img16)
  38. ```
  39. ![pixelated 16x16](media/pixel/output_3_0.png)
  40. We can try a few different shrinkage sizes.
  41. 32x32 seems to work the best.
  42. ```python
  43. img32 = pixelate(img, 32, 32)
  44. img64 = pixelate(img, 64, 64)
  45. printI2(img32, img64)
  46. ```
  47. ![pixelated 32x42, 64x64](media/pixel/output_4_0.png)
  48. ```python
  49. img8 = pixelate(img, 8, 8)
  50. printI(img8)
  51. ```
  52. ![original image 8x8 pixelated](media/pixel/output_5_0.png)
  53. Despite the images being pixelated, they have imperfections that normal pixel art wouldn't have.
  54. To remove the noise and make it look smoother, we will do k-means clustering on the pixelated images.
  55. K-means will reduce the number of colors in the image and eliminate any noise.
  56. Most of the clustering code is from my blog post: [Image Clustering with K-means](https://jrtechs.net/data-science/image-clustering-with-k-means)
  57. ```python
  58. import skimage
  59. from sklearn.cluster import KMeans
  60. from numpy import linalg as LA
  61. import numpy as np
  62. def colorClustering(idx, img, k):
  63. clusterValues = []
  64. for _ in range(0, k):
  65. clusterValues.append([])
  66. for r in range(0, idx.shape[0]):
  67. for c in range(0, idx.shape[1]):
  68. clusterValues[idx[r][c]].append(img[r][c])
  69. imgC = np.copy(img)
  70. clusterAverages = []
  71. for i in range(0, k):
  72. clusterAverages.append(np.average(clusterValues[i], axis=0))
  73. for r in range(0, idx.shape[0]):
  74. for c in range(0, idx.shape[1]):
  75. imgC[r][c] = clusterAverages[idx[r][c]]
  76. return imgC
  77. ```
  78. ```python
  79. def segmentImgClrRGB(img, k):
  80. imgC = np.copy(img)
  81. h = img.shape[0]
  82. w = img.shape[1]
  83. imgC.shape = (img.shape[0] * img.shape[1], 3)
  84. #5. Run k-means on the vectorized responses X to get a vector of labels (the clusters);
  85. #
  86. kmeans = KMeans(n_clusters=k, random_state=0).fit(imgC).labels_
  87. #6. Reshape the label results of k-means so that it has the same size as the input image
  88. # Return the label image which we call idx
  89. kmeans.shape = (h, w)
  90. return kmeans
  91. ```
  92. ```python
  93. def kMeansImage(image, k):
  94. idx = segmentImgClrRGB(image, k)
  95. return colorClustering(idx, image, k)
  96. printI(kMeansImage(img, 5))
  97. ```
  98. ![original image with k means of 5](media/pixel/output_9_0.png)
  99. Running the k-means algorithm on the 32x32 bit image produces a cool look.
  100. ```python
  101. printI(kMeansImage(img32, 3))
  102. ```
  103. ![32 bit k-means of 3 clusters](media/pixel/output_10_0.png)
  104. We can compare the original, pixelated, and clustered images side by side.
  105. ```python
  106. def printI3(i1, i2, i3):
  107. fig = plt.figure(figsize=(18,6))
  108. ax1 = fig.add_subplot(1,3,1)
  109. ax1.imshow(cv2.cvtColor(i1, cv2.COLOR_BGR2RGB))
  110. ax2 = fig.add_subplot(1,3,2)
  111. ax2.imshow(cv2.cvtColor(i2, cv2.COLOR_BGR2RGB))
  112. ax3 = fig.add_subplot(1,3,3)
  113. ax3.imshow(cv2.cvtColor(i3, cv2.COLOR_BGR2RGB))
  114. plt.savefig('trifecta.png')
  115. printI3(img, img32, kMeansImage(img32, 3))
  116. ```
  117. ![original, pixelated, k-means](media/pixel/output_11_0.png)