前言
參考的一些文章以及論文我都會給大家分享出來 —— 鏈接就貼在原文,論文我上傳到資源中去,大家可以免費下載學(xué)習(xí),如果當(dāng)天資源區(qū)找不到論文,那就等等,可能正在審核,審核完后就可以下載了。大家一起學(xué)習(xí),一起進(jìn)步!加油!!
圖像特效處理一般是對圖像的像素點的通道、灰度值值等進(jìn)行操作,達(dá)到想要的結(jié)果,下面將會給大家一一呈現(xiàn)一些簡單特效的原理以及代碼實現(xiàn),希望能夠?qū)Υ蠹矣幸欢ǖ膸椭?/p>
話不多說,先是本系列文章的經(jīng)典操作之讀取圖像信息:
""" Author:XiaoMa date:2021/11/16 """ import cv2 import numpy as np import math import matplotlib.pyplot as plt img0 = cv2.imread('E:\From Zhihu\For the desk\cvfifteen1.jpg') img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY) h, w = img0.shape[:2] print(h, w) cv2.imshow("W0", img0) cv2.imshow("W1", img1) cv2.waitKey(delay = 0)
得到的圖像信息如下:
386 686
1. 毛玻璃特效
毛玻璃特效的原理是在當(dāng)前的像素點的鄰域內(nèi)隨機取一個像素點來代替它,從而達(dá)到一個毛玻璃的模糊的效果。代碼如下,已經(jīng)添加了注釋,如果有看不懂的地方評論區(qū)留言大家一起討論。
#毛玻璃特效 img2 = np.zeros((h, w, 3), np.uint8) #生成與原圖像等大的全零矩陣 for i in range(0, h - 6): #防止下面的隨機數(shù)超出邊緣 for j in range(0, w - 6): index = int(np.random.random()*6) #0~6的隨機數(shù) (b, g, r) = img0[i + index, j + index] img2[i, j] = (b, g, r) cv2.imshow("W2", img2) cv2.waitKey(delay = 0)
得到的效果如下:
由于取隨機數(shù)的時候必須要減去邊緣的那些像素點值,所以圖像的右邊界和下邊界不可避免的出現(xiàn)了未填充區(qū)域。
在寫博客的時候突然心生一計,如果我們在創(chuàng)建全零矩陣時就對邊界進(jìn)行限定不就可以了嘛,試了一下,果然可以!!如下:
#毛玻璃特效 img2 = np.zeros((h - 6, w - 6, 3), np.uint8) #生成的全零矩陣考慮到了隨機數(shù)范圍,變小了 for i in range(0, h - 6): #防止下面的隨機數(shù)超出邊緣 for j in range(0, w - 6): index = int(np.random.random()*6) #0~6的隨機數(shù) (b, g, r) = img0[i + index, j + index] img2[i, j] = (b, g, r) cv2.imshow("W2", img2) cv2.waitKey(delay = 0)
經(jīng)過上述方式生成的毛玻璃特效就不會出現(xiàn)未填充部位,但圖像的尺寸確實小了。
2. 浮雕特效
Python 實現(xiàn)浮雕特效的原理是先勾勒出圖像的邊界曲線,然后降低邊界周圍的像素值,從而得到一幅立體的浮雕形式的圖像。
#浮雕特效(需要對灰度圖像進(jìn)行操作) img3 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w - 2): #減2的效果和上面一樣 grayP0 = int(img1[i, j]) grayP1 = int(img1[i, j + 2]) #取與前一個像素點相鄰的點 newP = grayP0 - grayP1 + 150 #得到差值,加一個常數(shù)可以增加浮雕立體感 if newP > 255: newP = 255 if newP < 0: newP = 0 img3[i, j] = newP cv2.imshow("W3", img3) cv2.waitKey(delay = 0)
得到效果如下:
3. 素描特效
該特效實現(xiàn)較為簡單,直接在代碼中給出注釋:
#素描特效 img4 = 255 - img1 #對原灰度圖像的像素點進(jìn)行反轉(zhuǎn) blurred = cv2.GaussianBlur(img4, (21, 21), 0) #進(jìn)行高斯模糊 inverted_blurred = 255 - blurred #反轉(zhuǎn) img4 = cv2.divide(img1, inverted_blurred, scale = 127.0) #灰度圖像除以倒置的模糊圖像得到鉛筆素描畫 cv2.imshow("W4", img4) cv2.waitKey(delay = 0)
4. 懷舊特效
懷舊特效需要專門的 R, G, B 通道的轉(zhuǎn)換公式來對圖像的三個通道進(jìn)行處理,轉(zhuǎn)換公式為:
實現(xiàn)代碼如下:
#懷舊特效 img5 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w): B = 0.272 * img0[i, j][2] + 0.534 * img0[i, j][1] + 0.131 * img0[i, j][0] G = 0.349 * img0[i, j][2] + 0.686 * img0[i, j][1] + 0.168 * img0[i, j][0] R = 0.393 * img0[i, j][2] + 0.769 * img0[i, j][1] + 0.189 * img0[i, j][0] if B > 255: B = 255 if G > 255: G = 255 if R > 255: R = 255 img5[i, j] = np.uint8((B, G, R)) cv2.imshow("W5", img5) cv2.waitKey(delay = 0)
得到效果如下:
這個特效計算量比起前面的幾種還是有點大的,需要對像素點進(jìn)行遍歷,然后計算每一個點的三個通道的值。
5. 流年特效
比起前面的懷舊特效,流年特效只需要對圖像的每一個像素點的藍(lán)色通道(B)進(jìn)行簡單調(diào)整就可以了,首先是對其開根號,然后乘以一個參數(shù)即可,實現(xiàn)代碼如下:
#流年特效 img6 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w): B = math.sqrt(img0[i, j][0]) *14 # B通道的數(shù)值開平方乘以參數(shù)14 G = img0[i, j][1] R = img0[i, j][2] if B > 255: B = 255 img6[i, j] = np.uint8((B, G, R)) cv2.imshow("W6", img6) cv2.waitKey(delay = 0)
大家可以多修改參數(shù)進(jìn)行調(diào)試,觀察不同的參數(shù)下的效果。
6. 水波特效
水波特效是使用三角函數(shù)得到波紋的傳遞函數(shù),然后根據(jù)設(shè)定的中心進(jìn)行特效的生成,該部分的算法有點難度,多嘗試幾次就可以了,以后博主有時間會專門出一片水波特效的介紹博文。實現(xiàn)代碼如下:
#水波特效 img7 = np.zeros((h, w, 3), np.uint8) wavelength = 20 #定義水波特效波長 amplitude = 30 #幅度 phase = math.pi / 4 #相位 centreX = 0.5 #水波中心點X centreY = 0.5 #水波中心點Y radius = min(h, w) / 2 icentreX = w*centreX #水波覆蓋寬度 icentreY = h*centreY #水波覆蓋高度 for i in range(0, h): for j in range(0, w): dx = j - icentreX dy = i - icentreY distance = dx * dx + dy * dy if distance > radius * radius: x = j y = i else: # 計算水波區(qū)域 distance = math.sqrt(distance) amount = amplitude * math.sin(distance / wavelength * 2 * math.pi - phase) amount = amount * (radius - distance) / radius amount = amount * wavelength / (distance + 0.0001) x = j + dx * amount y = i + dy * amount # 邊界判斷 if x < 0: x = 0 if x >= w - 1: x = w - 2 if y < 0: y = 0 if y >= h - 1: y = h - 2 p = x - int(x) q = y - int(y) # 圖像水波賦值 img7[i, j, :] = (1 - p) * (1 - q) * img0[int(y), int(x), :] + p * (1 - q) * img0[int(y), int(x), :] + (1 - p) * q * img0[int(y), int(x), :] + p * q * img0[int(y), int(x), :] cv2.imshow("W7", img7) cv2.waitKey(delay = 0)
得到效果如下:
由于這張圖片剛好波紋附近是頭發(fā),導(dǎo)致得到的波紋顯得不太清晰,可以換幾張圖片嘗試一下,看看該算法的效果。
7. 卡通特效
該特效主要原理是提取圖像的邊界輪廓,然后和原圖像相與得到最終的卡通化效果,代碼如下,已添加注釋:
#卡通特效 num_bilateral = 7 #定義雙邊濾波的數(shù)目 for i in range(num_bilateral): #雙邊濾波處理,除去噪聲,保留邊界 img_color = cv2.bilateralFilter(img0, d = 9, sigmaColor = 5, sigmaSpace = 3) img_blur = cv2.medianBlur(img1, 7) # 中值濾波處理 img_edge = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize = 5, C = 2) #邊緣檢測及自適應(yīng)閾值化處理,提取邊界 img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB) #轉(zhuǎn)換回彩色圖像 img8 = cv2.bitwise_and(img0, img_edge) #圖像的與運算 cv2.imshow('W8', img8) cv2.waitKey(delay = 0)
得到效果如下:
如果對實現(xiàn)的效果不滿意,可以不斷調(diào)整雙邊濾波和中值濾波的參數(shù),直到找到較為滿意的效果。
8. 將圖像都匯總到一張圖中
基礎(chǔ)操作,沒啥可注釋的,直接上代碼:
#將所有圖像保存到一張圖中 plt.rcParams['font.family'] = 'SimHei' imgs = [img0, img1, img2, img3, img4, img5, img6, img7, img8] titles = ['原圖', '灰度圖', '毛玻璃特效', '浮雕特效', '素描特效', '懷舊特效', '流年特效', '水波特效', '卡通特效'] for i in range(9): imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB) plt.subplot(3, 3, i + 1) plt.imshow(imgs[i]) plt.title(titles[i]) plt.xticks([]) plt.yticks([]) plt.suptitle('圖像特效處理') plt.savefig('E:\From Zhihu\For the desk\cvfifteenresult.jpg', dpi = 1080) plt.show()
得到最終的總圖 :
9. 總體代碼
修改一下圖像讀取路徑就可以使用了。還是那句話,建議從頭慢慢來一遍,當(dāng)然如果你只是想給女朋友生成一張素描或者浮雕的話那就無所謂了哈哈哈。
""" Author:XiaoMa date:2021/11/16 """ import cv2 import numpy as np import math import matplotlib.pyplot as plt img0 = cv2.imread('E:\From Zhihu\For the desk\cvfifteen1.jpg') img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY) h, w = img0.shape[:2] print(h, w) cv2.imshow("W0", img0) cv2.imshow("W1", img1) cv2.waitKey(delay = 0) #毛玻璃特效 img2 = np.zeros((h - 6, w - 6, 3), np.uint8) #生成的全零矩陣考慮到了隨機數(shù)范圍,變小了 for i in range(0, h - 6): #防止下面的隨機數(shù)超出邊緣 for j in range(0, w - 6): index = int(np.random.random()*6) #0~6的隨機數(shù) (b, g, r) = img0[i + index, j + index] img2[i, j] = (b, g, r) cv2.imshow("W2", img2) cv2.waitKey(delay = 0) #浮雕特效(需要對灰度圖像進(jìn)行操作) img3 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w - 2): #減2的效果和上面一樣 grayP0 = int(img1[i, j]) grayP1 = int(img1[i, j + 2]) #取與前一個像素點相鄰的點 newP = grayP0 - grayP1 + 150 #得到差值,加一個常數(shù)可以增加浮雕立體感 if newP > 255: newP = 255 if newP < 0: newP = 0 img3[i, j] = newP cv2.imshow("W3", img3) cv2.waitKey(delay = 0) #素描特效 img4 = 255 - img1 #對原灰度圖像的像素點進(jìn)行反轉(zhuǎn) blurred = cv2.GaussianBlur(img4, (21, 21), 0) #進(jìn)行高斯模糊 inverted_blurred = 255 - blurred #反轉(zhuǎn) img4 = cv2.divide(img1, inverted_blurred, scale = 127.0) #灰度圖像除以倒置的模糊圖像得到鉛筆素描畫 cv2.imshow("W4", img4) cv2.waitKey(delay = 0) #懷舊特效 img5 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w): B = 0.272 * img0[i, j][2] + 0.534 * img0[i, j][1] + 0.131 * img0[i, j][0] G = 0.349 * img0[i, j][2] + 0.686 * img0[i, j][1] + 0.168 * img0[i, j][0] R = 0.393 * img0[i, j][2] + 0.769 * img0[i, j][1] + 0.189 * img0[i, j][0] if B > 255: B = 255 if G > 255: G = 255 if R > 255: R = 255 img5[i, j] = np.uint8((B, G, R)) cv2.imshow("W5", img5) cv2.waitKey(delay = 0) #流年特效 img6 = np.zeros((h, w, 3), np.uint8) for i in range(0, h): for j in range(0, w): B = math.sqrt(img0[i, j][0]) *14 # B通道的數(shù)值開平方乘以參數(shù)14 G = img0[i, j][1] R = img0[i, j][2] if B > 255: B = 255 img6[i, j] = np.uint8((B, G, R)) cv2.imshow("W6", img6) cv2.waitKey(delay = 0) #水波特效 img7 = np.zeros((h, w, 3), np.uint8) wavelength = 20 #定義水波特效波長 amplitude = 30 #幅度 phase = math.pi / 4 #相位 centreX = 0.5 #水波中心點X centreY = 0.5 #水波中心點Y radius = min(h, w) / 2 icentreX = w*centreX #水波覆蓋寬度 icentreY = h*centreY #水波覆蓋高度 for i in range(0, h): for j in range(0, w): dx = j - icentreX dy = i - icentreY distance = dx * dx + dy * dy if distance > radius * radius: x = j y = i else: # 計算水波區(qū)域 distance = math.sqrt(distance) amount = amplitude * math.sin(distance / wavelength * 2 * math.pi - phase) amount = amount * (radius - distance) / radius amount = amount * wavelength / (distance + 0.0001) x = j + dx * amount y = i + dy * amount # 邊界判斷 if x < 0: x = 0 if x >= w - 1: x = w - 2 if y < 0: y = 0 if y >= h - 1: y = h - 2 p = x - int(x) q = y - int(y) # 圖像水波賦值 img7[i, j, :] = (1 - p) * (1 - q) * img0[int(y), int(x), :] + p * (1 - q) * img0[int(y), int(x), :] + (1 - p) * q * img0[int(y), int(x), :] + p * q * img0[int(y), int(x), :] cv2.imshow("W7", img7) cv2.waitKey(delay = 0) #卡通特效 num_bilateral = 7 #定義雙邊濾波的數(shù)目 for i in range(num_bilateral): #雙邊濾波處理 img_color = cv2.bilateralFilter(img0, d = 9, sigmaColor = 5, sigmaSpace = 3) img_blur = cv2.medianBlur(img1, 7) # 中值濾波處理 img_edge = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize = 5, C = 2) #邊緣檢測及自適應(yīng)閾值化處理 img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB) #轉(zhuǎn)換回彩色圖像 img8 = cv2.bitwise_and(img0, img_edge) #圖像的與運算 cv2.imshow('W8', img8) cv2.waitKey(delay = 0) #將所有圖像保存到一張圖中 plt.rcParams['font.family'] = 'SimHei' imgs = [img0, img1, img2, img3, img4, img5, img6, img7, img8] titles = ['原圖', '灰度圖', '毛玻璃特效', '浮雕特效', '素描特效', '懷舊特效', '流年特效', '水波特效', '卡通特效'] for i in range(9): imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB) plt.subplot(3, 3, i + 1) plt.imshow(imgs[i]) plt.title(titles[i]) plt.xticks([]) plt.yticks([]) plt.suptitle('圖像特效處理') plt.savefig('E:\From Zhihu\For the desk\cvfifteenresult.jpg', dpi = 1080) plt.show()
結(jié)束語
本篇文章總結(jié)了圖像特效處理中的毛玻璃、浮雕、素描等一些操作的原理和簡單實現(xiàn),對于一些比較復(fù)雜的算法后面有時間再專門寫一篇博文進(jìn)行介紹,還有油畫特效本文也沒有介紹,由于該特效算法也和水波特效一樣有難度,所以后面等更新完這個系列我再慢慢補坑吧。
到此這篇關(guān)于Python 計算機視覺編程進(jìn)階之圖像特效處理篇的文章就介紹到這了,更多相關(guān)Python 圖像特效處理內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/qq_52309640/article/details/120941346