本期文章中,讓我們一起來學習以下內容。
透過PIL和OpenCV來使用一些常見的影象處理技術,例如將RGB影象轉換為灰度影象、旋轉影象、對影象進行消噪、檢測影象中的邊緣以及裁剪影象中的感興趣區域。使用OpenCV中的模板匹配搜尋影象中的物件。所需安裝的庫:PIL、OpenCV、imutils
為什麼我們需要學習影象處理技術?
深度學習對於影象的分析、識別以及語義理解具有重要意義。“影象分類”、“物件檢測”、“例項分割”等是深度學習在影象中的常見應用。為了能夠建立更好的訓練資料集,我們必須先深入瞭解基本的影象處理技術,例如影象增強,包括裁剪影象、影象去噪或旋轉影象等。其次基本的影象處理技術同樣有助於光學字元識別(OCR)。
影象處理技術透過識別關鍵特徵或讀取影象中的文字資訊,來提高影象的可解釋性,以便對影象中存在的物件進行分類或檢測。
此處提供程式碼和影象
匯入所需的庫
import cv2from PIL import Image
首先我們使用OpenCV和PIL顯示影象
使用OpenCV讀取和顯示影象
image = cv2.imread(r'love.jpg')cv2.imshow("Image", image)cv2.waitKey(0)
如果影象太大,影象的視窗將不匹配螢幕顯示比例。
那麼如何在螢幕上顯示完整的影象?
預設情況下,顯示超大影象時影象都會被裁剪,不能被完整顯示出來。為了能夠查
看完整影象,我們將使用OpenCV中的namedWindow(name, flag)來建立一個新的顯示影象視窗。
第一個引數name是視窗的標題,將被用作識別符號。 當您將flag設定為cv2.WINDOW_NORMAL時,將顯示完整影象,並可以調整視窗大小。當然flag引數還有選擇。
image = cv2.imread(r'love.jpg')cv2.namedWindow('Normal Window', cv2.WINDOW_NORMAL)cv2.imshow('Normal Window', image)cv2.waitKey(0)
調整影象的尺寸
當我們調整影象大小時,我們可以更改影象的高度或寬度,或在保持寬高比不變的情況下同時變化高度和寬度。圖片的寬高比是圖片的寬度與高度的比。
image= cv2.imread(r'taj.jpg')scale_percent =200 # percent of original sizewidth = int(image.shape[1] * scale_percent / 100)height = int(image.shape[0] * scale_percent / 100)dim = (width, height)resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)cv2.imshow("Resize", resized)cv2.waitKey(0)
使用PIL讀取和顯示影象
我們將使用open()載入影象,然後使用show()進行顯示。
使用image.show()建立一個臨時檔案
pil_image= Image.open(r'love.jpg')pil_image.show("PIL Image")
如果我們對影象中目標的邊緣或其他特徵感興趣,要如何對他們進行識別呢?
灰度影象常常用於識別目標物體的邊緣,因為灰度影象不僅助於理解影象中對比度、陰影漸變,而且有助於理解影象特徵。
與灰度影象的2D通道相比,RGB影象具有三個通道:紅色,綠色和藍色。與彩色影象相比,灰度影象每個畫素的資訊更少,因此灰度影象的處理時間將更快。
使用OpenCV對彩色影象進行灰度縮放
以下是使用cvtColor()將彩色影象轉換為灰度影象的方法及轉換結果。
image = cv2.imread(r'love.jpg')gray_image= cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)cv2.namedWindow('Gray Image', cv2.WINDOW_NORMAL)cv2.imshow('Gray Image', gray_image)cv2.waitKey(0)
完成轉換的灰度圖
使用PIL對彩色影象進行灰度縮放
convert()提供了此影象轉換的另一種方式, “ L”模式用於轉換為灰度影象,“ RGB”模式用於轉換為彩色影象。
pil_image= Image.open(r'love.jpg')gray_pil=pil_image.convert('L')gray_pil.show()
使用OpenCV進行邊緣檢測
我們將使用Canny運算元對影象中的邊緣進行檢測。Canny邊緣檢測是透過灰度影象,使用高階演算法完成的。
Canny():第一個引數是輸入影象,第二個和第三個引數是閾值1和閾值2的值。
image= cv2.imread(r'taj.jpg')cv2.namedWindow("Edge", cv2.WINDOW_NORMAL)denoised_image = cv2.Canny(image, 100,200 )cv2.imshow("Edge", denoised_image)cv2.waitKey(0)
Canny邊緣處理
如果影象發生一定的傾斜或旋轉,應該怎樣進行調整?
OCR對傾斜文字的提取效果不佳,因此我們需要對原影象進行校正。可以使用OpenCV和PIL中的rotate()對影象進行角度校正。
使用OpenCV旋轉影象
rotate()會依據函式中的第二個引數rotationCode的值來旋轉影象。
旋轉引數值有以下幾種:
cv2.ROTATE_90_CLOCKWISEcv2. ROTATE_90_COUNTERCLOCKWISEcv2.ROTATE_180image = cv2.imread(r'love.jpg')cv2.namedWindow("Rotated Image", cv2.WINDOW_NORMAL)rotated_img= cv2.rotate(image,cv2.ROTATE_90_CLOCKWISE )cv2.imshow("Rotated Image", rotated_img)cv2.waitKey(0)
使用OpenCV將影象順時針旋轉90度
如果我們想將影象旋轉特定角度怎麼辦?
根據特定角度旋轉影象
在下面的程式碼中,影象以60度為增量旋轉
使用 imutils中的rotate()
import imutilsimport numpy as npimage = cv2.imread(r'love.jpg')# loop over the rotation anglesfor angle in np.arange(0, 360, 60): cv2.namedWindow("Rotated", cv2.WINDOW_NORMAL) rotated = imutils.rotate(image, angle) cv2.imshow("Rotated", rotated) cv2.waitKey(0)
使用imutils以60度為增量旋轉影象
使用PIL旋轉影象
此處使用PIL將影象旋轉110度
pil_image= Image.open(r'love.jpg')rotate_img_pil=pil_image.rotate(110)rotate_img_pil.show()
使用PIL將影象旋轉110度
當影象因噪聲而變差並影響影象分析時,我們應該如何提高影象質量?
使用OpenCV對影象進行除噪
噪聲並不是我們想得到的訊號,就影象而言,它會使影象受到干擾而失真。
使用OpenCV最小化影象中出現的噪聲,首先輸入含有噪聲的影象
image= cv2.imread(r'taj.jpg')cv2.namedWindow("Noised Image", cv2.WINDOW_NORMAL)cv2.imshow("Noised Image", image)cv2.waitKey(0)
OpenCV有多種方法可以消除影象中的噪點。我們將使用cv.fastNlMeansDenoisingColored(),來消除彩色影象中的噪點。
fastNIMeansDenoising函式的常見引數:
src: 源影象dst: 輸出與src具有相同大小和型別的影象h: 調節過濾器強度。 較高的h值可以完全消除噪點和影象細節,較小的h值可以保留影象細節以及一些噪點。hForColorComponents: 與h相同,但僅用於彩色影象,通常與h相同templateWindowSize: 預設0(推薦7)searchWindowSize: 預設0(推薦21)image= cv2.imread(r'taj.jpg')cv2.namedWindow("Denoised Image", cv2.WINDOW_NORMAL)denoised_image = cv2.fastNlMeansDenoisingColored(image,None, h=5)cv2.imshow("Denoised Image", denoised_image)cv2.waitKey(0)
如何從影象中提取某些感興趣的區域?
裁剪影象
裁剪影象可讓我們提取影象中的興趣區域。
使用OpenCV裁剪影象
在OpenCV中裁剪是透過將影象陣列切成薄片來進行的,我們先傳遞y座標的起點和終點,然後傳遞x座標的起點和終點。
image[y_start:y_end, x_start:x_end]
image= cv2.imread(r'taj.jpg')resized_img= image[15:170, 20:200]cv2.imshow("Resize", resized_img)cv2.waitKey(0)
使用PIL裁剪影象
PIL的crop()允許我們裁剪影象的矩形區域。crop()的引數是矩形左上角和右下角的畫素座標。
pil_image = Image.open(r'taj.jpg')# Get the Size of the image in pixels width, height = pil_image.size# Setting the cropped image co-ordinatesleft = 3top = height /25right = 200bottom = 3 * height / 4# Crop the image based on the above dimension cropped_image = pil_image.crop((left, top, right, bottom))# Shows the image in image viewer cropped_image.show()
模板匹配
我們可以提供模板和OpenCV中的matchTemplate()在影象中搜索該模板並提取其位置。
這個模板會像卷積神經網路一樣在整個影象上滑動,並嘗試將模板與輸入影象進行匹配。
minMaxLoc()用於獲取最大值/最小值,它是透過矩形的左上角開始沿著寬度和高度獲取值。
模板匹配有6種方法:
cv2.TM_SQDIFFcv2.TM_SQDIcv2.TM_Ccv2.TM_CCORR_NORMEDcv2.TM_CCOEFFcv2.TM_CCOEFF_NORMED在下面的示例中,我們將從主圖中裁剪一小部分建立模板。
用於模板匹配的方法是TM_CCOEFF_NORMED。匹配的閾值設定為0.95。當匹配機率大於0.95時,該函式將會在與該匹配相對應的區域周圍繪製一個矩形。
import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread(r'love.jpg',0)cv2.imshow("main",img)cv2.waitKey(0)template = cv2.imread(r'template1.png',0)cv2.imshow("Template",template)cv2.waitKey(0)w, h = template.shape[::-1]methods = [ 'cv2.TM_CCOEFF_NORMED']for meth in methods: method = eval(meth)# Apply template Matching res = cv2.matchTemplate(img,template,method) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) threshold=0.95 loc=np.where(res>threshold) if len(loc[0])>0:# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum if method in [ cv2.TM_SQDIFF_NORMED]: top_left = min_loc bottom_right = (top_left[0] + w, top_left[1] + h)cv2.rectangle(img,top_left, bottom_right,100,20)plt.subplot(121),plt.imshow(res,cmap = 'gray') plt.title('Matching Result'), plt.xticks([]), plt.yticks([]) plt.subplot(122),plt.imshow(img,cmap = 'gray') plt.title('Detected Point'), plt.xticks([]), plt.yticks([]) plt.suptitle(meth)plt.show() else: print("Template not matched")
結論