天天看點

Python 讓圖像變卡通圖

要創造卡通效果,我們需要注意兩件事: 邊緣和調色闆,這就是照片和卡通的不同之處。為了調整這兩個主要組成部分,我們将經曆四個主要步驟:

  • 加載圖像
  • 建立邊緣
  • 減少調色闆
  • 将邊緣掩模與彩色圖像結合
  1. 圖檔導入
import cv2
import numpy as np
img = cv2.imread('xingye.jpg')
cv2.imshow('origin', img)
cv2.waitKey(0)
cv2.destroyAllWindows()      
import cv2import numpy as npimg = cv2.imread('xingye.jpg')cv2.imshow('origin', img)cv2.waitKey(0)cv2.destroyAllWindows()      
Python 讓圖像變卡通圖

2. 建立邊緣掩模

卡通效果強調圖像邊緣的寬度,使用 cv2.adaptiveThreshold()函數檢測圖像的邊緣。

def edge_mask(img, line_size, blur_value):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_blur = cv2.medianBlur(gray, blur_value)
    edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, line_size, blur_value)
    return edges      

在上面函數中先将圖像轉換為灰階圖像。然後,利用 cv2.medianBlur 函數對模糊灰階圖像進行去噪處理。模糊值越大,圖像中出現的黑噪聲越少。然後,應用 adaptiveThreshold 函數,并定義邊緣的線條大小。更大的線條尺寸意味着更寬的邊緣,這将在圖像中得到展示。

line_size = 7
blur_value = 7
edges = edge_mask(img, line_size, blur_value)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()      
Python 讓圖像變卡通圖

3. 減少調色闆

照片和繪畫的主要差別(就顔色而言)在于每張照片中不同顔色的數量,其中繪畫的圖像的顔色比照片少。是以,我們使用量化的方式來減少照片中的顔色數量。

為了實作這個圖像量化,我們應用了 OpenCV 庫提供的 K-Means 算法。為了使下一步更容易,我們可以定義 color_quantization 函數如下。

line_size = 7
blur_value = 7
edges = edge_mask(img, line_size, blur_value)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()      

k 值是我們想要應用到圖像的顔色數量

total_color = 9
img = color_quantization(img, total_color)      

雙邊濾波器

做完圖像量化後,我們可以通過使用雙邊濾波器來降低圖像中的噪聲。這會給圖像帶來一點模糊和銳度降低的效果。

blurred = cv2.bilateralFilter(img, d=7, sigmaColor=200, sigmaSpace=200)      

調整以下三個參數:

  • d:每個像素鄰域的直徑
  • sigmaColor:顔色空間濾波器的sigma值。這個參數的值越大,就表明該像素鄰域内有更寬廣的顔色會被混合到一起,産生較大的半相等顔色區域。
  • sigmaSpace:坐标空間中濾波器的sigma值,坐标空間的标注方差。他的數值越大,意味着越遠的像素會互相影響,進而使更大的區域足夠相似的顔色擷取相同的顔色。

4. 邊緣掩模和彩色圖像結合

最後一步是将我們前面建立的邊緣掩模與經過顔色處理的圖像結合起來。為此,可以使用 cv2.bitwise_and 函數

cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)
cv2.imshow('cartoon', cartoon)
cv2.waitKey(0)
cv2.destroyAllWindows()      
import cv2
import numpy as np


def edge_mask(img, line_size, blur_value):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_blur = cv2.medianBlur(gray, blur_value)
    edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, line_size, blur_value)
    return edges


img = cv2.imread('xingye.jpg')
cv2.imshow('origin', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

line_size = 7
blur_value = 7
edges = edge_mask(img, line_size, blur_value)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()


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


total_color = 9
img = color_quantization(img, total_color)

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

cv2.imshow('cartoon', cartoon)
cv2.waitKey(0)
cv2.destroyAllWindows()      

繼續閱讀