摘要:本文主要講述如何進行圖像量化處理和採樣處理及局部馬賽克特效。 本文分享自華為雲社區《[Python圖像處理] 二十.圖像量化處理和採樣處理及局部馬賽克特效》,作者: eastmount。 本文主要講述如何進行圖像量化處理和採樣處理及局部馬賽克特效。 一.圖像量化處理 圖像通常是自然界景物的客觀 ...
摘要:本文主要講述如何進行圖像量化處理和採樣處理及局部馬賽克特效。
本文分享自華為雲社區《[Python圖像處理] 二十.圖像量化處理和採樣處理及局部馬賽克特效》,作者: eastmount。
本文主要講述如何進行圖像量化處理和採樣處理及局部馬賽克特效。
一.圖像量化處理
圖像通常是自然界景物的客觀反映,並以照片形式或視頻記錄的介質連續保存,獲取圖像的目標是從感知的數據中產生數字圖像,因此需要把連續的圖像數據離散化,轉換為數字化圖像,其工作主要包括兩方面——量化和採樣。數字化幅度值稱為量化,數字化坐標值稱為採樣。本章主要講解圖像量化和採樣處理的概念,並通過Python和OpenCV實現這些功能。
1.1 概述
所謂量化(Quantization),就是將圖像像素點對應亮度的連續變化區間轉換為單個特定值的過程,即將原始灰度圖像的空間坐標幅度值離散化。量化等級越多,圖像層次越豐富,灰度解析度越高,圖像的質量也越好;量化等級越少,圖像層次欠豐富,灰度解析度越低,會出現圖像輪廓分層的現象,降低了圖像的質量。圖6-1是將圖像的連續灰度值轉換為0至255的灰度級的過程。
如果量化等級為2,則將使用兩種灰度級表示原始圖片的像素(0-255),灰度值小於128的取0,大於等於128的取128;如果量化等級為4,則將使用四種灰度級表示原始圖片的像素,新圖像將分層為四種顏色,0-64區間取0,64-128區間取64,128-192區間取128,192-255區間取192;依次類推。
圖6-2是對比不同量化等級的“Lena”圖。其中(a)的量化等級為256,(b)的量化等級為64,(c)的量化等級為16,(d)的量化等級為8,(e)的量化等級為4,(f)的量化等級為2。
1.2 操作
下麵講述Python圖像量化處理相關代碼操作。其核心流程是建立一張臨時圖片,接著迴圈遍歷原始圖像中所有像素點,判斷每個像素點應該屬於的量化等級,最後將臨時圖像顯示。下述代碼將灰度圖像轉換為兩種量化等級。
# -*- coding: utf-8 -*- import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('lena.png') #獲取圖像高度和寬度 height = img.shape[0] width = img.shape[1] #創建一幅圖像 new_img = np.zeros((height, width, 3), np.uint8) #圖像量化操作 量化等級為2 for i in range(height): for j in range(width): for k in range(3): #對應BGR三分量 if img[i, j][k] < 128: gray = 0 else: gray = 128 new_img[i, j][k] = np.uint8(gray) #顯示圖像 cv2.imshow("src", img) cv2.imshow("", new_img) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
其輸出結果如圖6-3所示,它將灰度圖像劃分為兩種量化等級。
下麵的代碼分別比較了量化等級為2、4、8的量化處理效果。
# -*- coding: utf-8 -*- import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('lena.png') #獲取圖像高度和寬度 height = img.shape[0] width = img.shape[1] #創建一幅圖像 new_img1 = np.zeros((height, width, 3), np.uint8) new_img2 = np.zeros((height, width, 3), np.uint8) new_img3 = np.zeros((height, width, 3), np.uint8) #圖像量化等級為2的量化處理 for i in range(height): for j in range(width): for k in range(3): #對應BGR三分量 if img[i, j][k] < 128: gray = 0 else: gray = 128 new_img1[i, j][k] = np.uint8(gray) #圖像量化等級為4的量化處理 for i in range(height): for j in range(width): for k in range(3): #對應BGR三分量 if img[i, j][k] < 64: gray = 0 elif img[i, j][k] < 128: gray = 64 elif img[i, j][k] < 192: gray = 128 else: gray = 192 new_img2[i, j][k] = np.uint8(gray) #圖像量化等級為8的量化處理 for i in range(height): for j in range(width): for k in range(3): #對應BGR三分量 if img[i, j][k] < 32: gray = 0 elif img[i, j][k] < 64: gray = 32 elif img[i, j][k] < 96: gray = 64 elif img[i, j][k] < 128: gray = 96 elif img[i, j][k] < 160: gray = 128 elif img[i, j][k] < 192: gray = 160 elif img[i, j][k] < 224: gray = 192 else: gray = 224 new_img3[i, j][k] = np.uint8(gray) #用來正常顯示中文標簽 plt.rcParams['font.sans-serif']=['SimHei'] #顯示圖像 titles = [u'(a) 原始圖像', u'(b) 量化-L2', u'(c) 量化-L4', u'(d) 量化-L8'] images = [img, new_img1, new_img2, new_img3] for i in xrange(4): plt.subplot(2,2,i+1), plt.imshow(images[i], 'gray'), plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
輸出結果如圖6-4所示,該代碼調用matplotlib.pyplot庫繪製了四幅圖像,其中(a)表示原始圖像,(b)表示等級為2的量化處理,(c)表示等級為4的量化處理,(d)表示等級為8的量化處理。
1.3 K-Means聚類量化處理
上一小節的量化處理是通過遍歷圖像中的所有像素點,進行灰度圖像的幅度值離散化處理。本小節補充一個基於K-Means聚類演算法的量化處理過程,它能夠將彩色圖像RGB像素點進行顏色分割和顏色量化。更多知識推薦大家學習前一篇文章。
# coding: utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('people.png') #圖像二維像素轉換為一維 data = img.reshape((-1,3)) data = np.float32(data) #定義中心 (type,max_iter,epsilon) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) #設置標簽 flags = cv2.KMEANS_RANDOM_CENTERS #K-Means聚類 聚集成4類 compactness, labels, centers = cv2.kmeans(data, 4, None, criteria, 10, flags) #圖像轉換回uint8二維類型 centers = np.uint8(centers) res = centers[labels.flatten()] dst = res.reshape((img.shape)) #圖像轉換為RGB顯示 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB) #用來正常顯示中文標簽 plt.rcParams['font.sans-serif']=['SimHei'] #顯示圖像 titles = [u'原始圖像', u'聚類量化 K=4'] images = [img, dst] for i in xrange(2): plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray'), plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
輸出結果如圖6-4所示,它通過K-Means聚類演算法將彩色人物圖像的灰度聚集成四種顏色。
二.圖像採樣處理
2.1 概述
圖像採樣(Image Sampling)處理是將一幅連續圖像在空間上分割成M×N個網格,每個網格用一個亮度值或灰度值來表示,其示意圖如圖6-5所示。
圖像採樣的間隔越大,所得圖像像素數越少,空間解析度越低,圖像質量越差,甚至出現馬賽克效應;相反,圖像採樣的間隔越小,所得圖像像素數越多,空間解析度越高,圖像質量越好,但數據量會相應的增大。圖6-6展示了不同採樣間隔的“Lena”圖。
2.2 操作
下麵講述Python圖像採樣處理相關代碼操作。其核心流程是建立一張臨時圖片,設置需要採樣的區域大小(如16×16),接著迴圈遍歷原始圖像中所有像素點,採樣區域內的像素點賦值相同(如左上角像素點的灰度值),最終實現圖像採樣處理。代碼是進行16×16採樣的過程。
# -*- coding: utf-8 -*- import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('scenery.png') #獲取圖像高度和寬度 height = img.shape[0] width = img.shape[1] #採樣轉換成16*16區域 numHeight = height/16 numwidth = width/16 #創建一幅圖像 new_img = np.zeros((height, width, 3), np.uint8) #圖像迴圈採樣16*16區域 for i in range(16): #獲取Y坐標 y = i*numHeight for j in range(16): #獲取X坐標 x = j*numwidth #獲取填充顏色 左上角像素點 b = img[y, x][0] g = img[y, x][1] r = img[y, x][2] #迴圈設置小區域採樣 for n in range(numHeight): for m in range(numwidth): new_img[y+n, x+m][0] = np.uint8(b) new_img[y+n, x+m][1] = np.uint8(g) new_img[y+n, x+m][2] = np.uint8(r) #顯示圖像 cv2.imshow("src", img) cv2.imshow("", new_img) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
輸出結果如下圖所示:
同樣,可以對彩色圖像進行採樣處理,下麵的代碼將彩色風景圖像採樣處理成8×8的馬賽克區域。
# -*- coding: utf-8 -*- import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('scenery.png') #獲取圖像高度和寬度 height = img.shape[0] width = img.shape[1] #採樣轉換成8*8區域 numHeight = height/8 numwidth = width/8 #創建一幅圖像 new_img = np.zeros((height, width, 3), np.uint8) #圖像迴圈採樣8*8區域 for i in range(8): #獲取Y坐標 y = i*numHeight for j in range(8): #獲取X坐標 x = j*numwidth #獲取填充顏色 左上角像素點 b = img[y, x][0] g = img[y, x][1] r = img[y, x][2] #迴圈設置小區域採樣 for n in range(numHeight): for m in range(numwidth): new_img[y+n, x+m][0] = np.uint8(b) new_img[y+n, x+m][1] = np.uint8(g) new_img[y+n, x+m][2] = np.uint8(r) #顯示圖像 cv2.imshow("src", img) cv2.imshow("Sampling", new_img) #等待顯示 cv2.waitKey(0) cv2.destroyAllWindows()
其輸出結果如圖所示,它將彩色風景圖像採樣成8×8的區域。
但上述代碼存在一個問題,當圖像的長度和寬度不能被採樣區域整除時,輸出圖像的最右邊和最下邊的區域沒有被採樣處理。這裡推薦讀者做個求餘運算,將不能整除部門的區域也進行採樣處理。
2.3 局部馬賽克處理
前面講述的代碼是對整幅圖像進行採樣處理,那麼如何對圖像的局部區域進行馬賽克處理呢?下麵的代碼就實現了該功能。當滑鼠按下時,它能夠給滑鼠拖動的區域打上馬賽克,並按下“s”鍵保存圖像至本地。
# -- coding:utf-8 -- import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 im = cv2.imread('people.png', 1) #設置滑鼠左鍵開啟 en = False #滑鼠事件 def draw(event, x, y, flags, param): global en #滑鼠左鍵按下開啟en值 if event==cv2.EVENT_LBUTTONDOWN: en = True #滑鼠左鍵按下並且移動 elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_LBUTTONDOWN: #調用函數打馬賽克 if en: drawMask(y,x) #滑鼠左鍵彈起結束操作 elif event==cv2.EVENT_LBUTTONUP: en = False #圖像局部採樣操作 def drawMask(x, y, size=10): #size*size採樣處理 m = x / size * size n = y / size * size print m, n #10*10區域設置為同一像素值 for i in range(size): for j in range(size): im[m+i][n+j] = im[m][n] #打開對話框 cv2.namedWindow('image') #調用draw函數設置滑鼠操作 cv2.setMouseCallback('image', draw) #迴圈處理 while(1): cv2.imshow('image', im) #按ESC鍵退出 if cv2.waitKey(10)&0xFF==27: break #按s鍵保存圖片 elif cv2.waitKey(10)&0xFF==115: cv2.imwrite('sava.png', im) #退出視窗 cv2.destroyAllWindows()
其輸出結果如圖所示,它將人物的臉部進行馬賽克處理。