手把手教你使用圖像處理利器OpenCV

2021-02-21 老齊教室

作者:Muhammad Junaid Khalid

翻譯:老齊

與本文相關的圖書推薦:《數據準備和特徵工程》

概要

在本文中,將學習如何使用Python語言進行圖像處理,我們不會局限於一個單獨的庫或框架,然而,有一個庫的使用率將會是最高的,那就是OpenCV。我們一開始會討論一些圖像處理,然後繼續探討不同的應用/場景,也就是圖像處理的用武之地。開始吧!

什麼是圖像處理?

在深入研究圖像處理的方法之前,重要的是要了解什麼是圖像處理,特別是這項技術在處理大量圖片方面的角色。圖像處理完整的說法是「數字圖像處理」,經常使用圖像處理的領域是「計算機視覺」。對這兩個術語不要混淆,圖像處理算法和計算機視覺(CV)算法都以圖像為輸入,然而,在圖像處理中,輸出也是圖像,而在計算機視覺中,輸出可以是關於圖像的一些特徵或信息。

為什麼需要圖像處理?

我們收集或生成的數據大部分是原始數據,也就是說,由於一些可能的原因,這些數據不適合直接用於應用程式。因此,我們需要首先分析它,執行必要的預處理,然後使用它——特別推薦《數據準備和特徵工程》,此書即為這方面最佳讀物。

例如,我們正在嘗試構建一個關於貓的分類器。我們的程序會把一個圖像作為輸入,然後告訴我們這個圖像是否包含一隻貓。構建這個分類器的第一步是收集數百張含有貓的圖片。一個常見的問題是,收集的所有圖片的大小都不相同,因此在將它們提供給模型進行訓練之前,需要調整它們的大小或者把它們進行預處理,使尺寸符合標準。

為什麼圖像處理對於任何計算機視覺應用序都是必不可少的?以上提到的只是眾多原因之一。

預備知識

為了輕鬆地學習本文內容,你需要已經具備如下知識。

首先,應該具備一定的程式語言技能,本文使用的是Python語言,如果尚未掌握此語言,推薦閱讀《跟老齊學Python:輕鬆入門》或《Python大學實用教程》。

其次,你應該了解什麼是機器學習以及它的基本工作原理。因為在本文中我們將使用一些機器學習算法來進行圖像處理。

另外,如果你之前接觸過或掌握了OpenCV的基本知識,也會有所幫助。但這不是必需的。

還有,你一定要了解圖像在內存中究竟是如何表示的。每幅圖像都由一組像素表示,即像素值矩陣。對於灰度圖像,像素值的範圍是0到255,它們表示該像素的強度。例如,如果你有一個20×20維的圖像,它將由一個20x20的矩陣表示(像素值總共是400)。

如果你正在處理彩色圖像,你應該知道它有三個通道——紅、綠、藍(RGB)。因此,一個彩色圖像有三個這樣的矩陣。

安裝

注意: 由於我們將通過Python使用OpenCV,所以你必須會實用它,前面推薦了關於Python的書籍。下面依次說明在不同作業系統中OpenCV的安裝方法:

$ pip install opencv-python

$ brew install opencv3 --with-contrib --with-python3

$ sudo apt-get install libopencv-dev python-opencv

要檢查是否安裝成功,請在Python交互模式中運行以下命令:

import cv2

必備的基礎知識

在進行圖像處理之前,要先做一些準備。

在本文中,我們將使用以下圖像:

注意: 為了在本文中顯示該圖像,對其進行了縮放,但是我們使用的圖像原始大小約為1180x786。

你可能注意到圖像現在是彩色的,這意味著它由三個顏色通道表示,即紅色、綠色和藍色。我們將把圖像轉換成灰度,並使用下面的代碼將圖像分割成單獨的通道。

找到圖像細節

使用imread()函數加載圖像後,我們可以得到關於它的一些簡單屬性,比如像素的數量和尺寸:

import cv2

img = cv2.imread('rose.jpg')

print("Image Properties")
print("- Number of Pixels: " + str(img.size))
print("- Shape/Dimensions: " + str(img.shape))

Output:

Image Properties
- Number of Pixels: 2782440
- Shape/Dimensions: (1180, 786, 3)

將圖像分割成單獨的通道

現在,我們將使用OpenCV將圖像分割成紅色、綠色和藍色的部分,並顯示它們:

from google.colab.patches import cv2_imshow

blue, green, red = cv2.split(img) # Split the image into its channels
img_gs = cv2.imread('rose.jpg', cv2.IMREAD_GRAYSCALE) # Convert image to grayscale

cv2_imshow(red) # Display the red channel in the image
cv2_imshow(blue) # Display the red channel in the image
cv2_imshow(green) # Display the red channel in the image
cv2_imshow(img_gs) # Display the grayscale version of image

為了簡單起見,我們只顯示灰度圖像。

圖像閾值

閾值的概念非常簡單。正如上面在圖像表示中所討論的,像素值可以是0到255之間的任何值。假設我們想要將一幅圖像轉二值化,即指定一個像素值為0或1。為此,我們可以設置閾值。例如,如果閾值(T)為125,那麼所有大於125的像素將被賦值為1,所有小於或等於該值的像素將被賦值為0。下面,我們通過代碼來更好地理解它。

將下面的圖像用上述方法進行轉換:

import cv2

# Read image
img = cv2.imread('image.png', 0)

# Perform binary thresholding on the image with T = 125
r, threshold = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY)
cv2_imshow(threshold)

輸出:

正如你所看到的, 二值化之後,出現了兩個區域,即黑色區域(像素值0)和白色區域(像素值1)。原來, 我們設置的閾值正好在圖像的中間,這就是為什麼黑白值在那裡被分割。

應用1:去除圖像中的噪聲

現在你已經對圖像處理的概念和用途有了基本的了解,接下來讓我們來了解一下它的一些具體應用。

在大多數情況下,我們收集的原始數據有噪聲,也就是說,不需要的特徵使圖像很難被感知。雖然這些圖像可以直接用於特徵抽取,但是算法的準確性會受到很大的影響。這就是為什麼在將圖像傳遞給算法以獲得更好的精度之前,要對圖像進行處理的原因。

有許多不同類型的噪聲,如高斯噪聲,椒鹽噪聲等。我們可以通過應用濾波器來去除圖像中的噪聲,或者至少將其影響降到最低。在濾波器方面也有很多選擇,每一個濾波器都有不同的優點。因此,對於特定類型的噪聲來說,總有一個是最好的。

為了更好地理解這一點,我們將在上面的玫瑰色圖像的灰度版本中添加「鹽和胡椒粉」噪聲,然後嘗試使用不同的濾波器去除圖像中的噪聲,看看哪一個最適合這種類型。

import numpy as np

# Adding salt & pepper noise to an image

def salt_pepper(prob):
# Extract image dimensions
row, col = img_gs.shape

# Declare salt & pepper noise ratio
s_vs_p = 0.5
output = np.copy(img_gs)

# Apply salt noise on each pixel individually
num_salt = np.ceil(prob * img_gs.size * s_vs_p)
coords = [np.random.randint(0, i - 1, int(num_salt))
for i in img_gs.shape]
output[coords] = 1

# Apply pepper noise on each pixel individually
num_pepper = np.ceil(prob * img_gs.size * (1. - s_vs_p))
coords = [np.random.randint(0, i - 1, int(num_pepper))
for i in img_gs.shape]
output[coords] = 0
cv2_imshow(output)

return output

# Call salt & pepper function with probability = 0.5
# on the grayscale image of rose
sp_05 = salt_pepper(0.5)

# Store the resultant image as 'sp_05.jpg'
cv2.imwrite('sp_05.jpg', sp_05)

好的,我們已經把噪聲添加到玫瑰圖像,這是它現在的樣子:

讓我們現在應用不同的濾波器,並記下觀察結果,即每個濾波器降噪的效果。

銳化濾波器
# Create our sharpening kernel, the sum of all values must equal to one for uniformity
kernel_sharpening = np.array([[-1,-1,-1],
[-1, 9,-1],
[-1,-1,-1]])

# Applying the sharpening kernel to the grayscale image & displaying it.
print("\n\n--- Effects on S&P Noise Image with Probability 0.5 ---\n\n")

# Applying filter on image with salt & pepper noise
sharpened_img = cv2.filter2D(sp_05, -1, kernel_sharpening)
cv2_imshow(sharpened_img)

在有椒鹽噪聲的圖像上應用濾波器得到的圖像如下所示。通過與原始灰度圖的對比,我們可以看出,它把圖像調得太亮了,也無法突出玫瑰上的亮點。因此,我們可以得出結論,銳化濾波器並不能去除噪聲。

銳化濾波器輸出:

中值濾波器
from scipy.ndimage import maximum_filter, minimum_filter

def midpoint(img):
maxf = maximum_filter(img, (3, 3))
minf = minimum_filter(img, (3, 3))
midpoint = (maxf + minf) / 2
cv2_imshow(midpoint)

print("\n\n---Effects on S&P Noise Image with Probability 0.5---\n\n")
midpoint(sp_05)

在有噪聲的圖像上應用中值濾波器,得到的圖像如下所示。通過與原始灰度圖像的對比,我們可以看出,與上面的核方法一樣,圖像的亮度調高了很多,然而,它能夠突出玫瑰上的亮斑(即噪聲)。因此,我們可以說,中值濾波器是比銳化濾波器更好的選擇,但它仍然不能完全恢復原始圖像。

中值濾波器輸出:

逆諧波均值濾波器

注意: 對這些濾波器的工作原理的闡述,超出了本文範疇,讀者可以在網上搜索,我們還是從應用的層面來研究。

def contraharmonic_mean(img, size, Q):
num = np.power(img, Q + 1)
denom = np.power(img, Q)
kernel = np.full(size, 1.0)
result = cv2.filter2D(num, -1, kernel) / cv2.filter2D(denom, -1, kernel)
return result

print("\n\n--- Effects on S&P Noise Image with Probability 0.5 ---\n\n")
cv2_imshow(contraharmonic_mean(sp_05, (3,3), 0.5))

在有椒鹽噪聲的圖像上應用逆諧波均值濾波器(https://en.wikipedia.org/wiki/Contraharmonic_mean)得到的圖像如下圖所示。通過與原始灰度圖像的對比,我們可以看到:它幾乎完美再現了原始圖像。它的強度或亮度級別與原圖是相同的,它突出了玫瑰上的亮點。因此,我們可以得出結論,逆諧波均值濾波器在處理椒鹽噪聲方面是非常有效的。

逆諧波均值濾波器輸出:

現在我們已經找到了最佳濾波器,它可以有效地把有噪聲的圖像恢復到原始圖像。我們可以繼續下一個應用了。

2:使用Canny算子進行邊緣檢測

到目前為止,我們使用的玫瑰圖像的背景是不變的,也就是黑色的,因此,我們將把這個應用用於不同的圖像,以更好地展示算法的功效。原因是,如果背景是恆定的,邊緣檢測任務就變得相當簡單,這不是我們所希望的。

在本文開始部分,我們提到了一個關於貓的分類器。現在我們延用這個例子,看看圖像處理如何在其中扮演一個完整的角色。

在分類算法中,首先掃描圖像尋找「對象」。也就是說,當你輸入一幅圖像時,算法會找到圖像中的所有對象,然後將它們與你試圖尋找的對象進行特徵比較。對於貓分類器,它會將在圖像中找到的所有對象與貓圖像的特徵進行比較,如果找到匹配項,它會告訴我們輸入圖像中包含了一隻貓。

對於這個貓分類器,僅以一張貓的圖像為例,以下是我們將要使用的圖像:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Declaring the output graph's size
plt.figure(figsize=(16, 16))

# Convert image to grayscale
img_gs = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('gs.jpg', img_gs)

# Apply canny edge detector algorithm on the image to find edges
edges = cv2.Canny(img_gs, 100,200)

# Plot the original image against the edges
plt.subplot(121), plt.imshow(img_gs)
plt.title('Original Gray Scale Image')
plt.subplot(122), plt.imshow(edges)
plt.title('Edge Image')

# Display the two images
plt.show()

邊緣檢測輸出:

正如你所看到的,圖像中包含對象的部分(在本例中是一隻貓)已經通過邊緣檢測用虛線標出或分隔開。現在你一定想知道,什麼是邊緣檢測的Canny算子,它是怎麼工作的?現在就討論一下。

要理解上述內容,需要討論三個關鍵步驟。首先,它對圖像進行降噪,降噪方式與前面討論的方式類似。其次,它使用每個像素的一階導數來找到邊緣。這背後的邏輯是,在邊緣存在的地方,會有一個突然的強度變化,導致一階導數值達到峰值,從而使該像素成為「邊緣像素」。

最後,進行滯後閾值化;上面我們說過,在一個邊緣的一階導數值會有一個峰值,但是我們沒有說:這個峰值需要有多高,才能被歸類為一個邊緣——這叫做閾值!在本文的前面,我們討論了什麼是簡單的閾值。遲滯閾值法是在此基礎上的一種改進,它利用兩個閾值來代替一個閾值。這背後的原因是,如果閾值過高,我們可能會錯過一些真正的邊緣(真負例),如果閾值過低,我們會得到很多被歸類為邊緣的點,而實際上不是邊緣(假正例)。一個閾值設置為高,一個設置為低,將所有高於「高閾值」的點標識為邊緣,然後對所有高於「低閾值」但低於「高閾值」的點進行評估;邊緣上的點確定之後,與邊緣點靠近或相鄰的點也被確定為邊緣,其餘的點被丟棄。

這些是Canny算子用於識別圖像邊緣的基本概念/方法。

譯者註: Canny算子是澳洲計算機科學家約翰·坎尼(John F. Canny)於1986年開發出來的一個多級邊緣檢測算法,其目標是找到一個最優的邊緣.

結論

在本文中,我們學習了如何在不同的平臺(如Windows、MacOS和Linux)上安裝OpenCV,以及如何驗證安裝成功。OpenCV是Python中最流行的圖像處理庫。

接著我們討論了什麼是圖像處理,以及它在機器學習的計算機視覺領域中的應用。我們討論了一些常見的噪聲類型,以及如何使用不同的濾波器將噪聲從圖像中去除,以便在應用中使用這些圖像。

此外,我們還了解了圖像處理如何在高端應用(如:對象檢測或分類)中發揮不可或缺的作用。請注意,這篇文章只是冰山一角,數字圖像處理還有更多的內容,不可能在一篇短文中全部涵蓋。請關注微信公眾號「老齊教室」,這裡還會刊發有關圖像處理的文章。

原文連結:https://stackabuse.com/introduction-to-image-processing-in-python-with-opencv/

搜索技術問答的公眾號:老齊教室

」★

在公眾號中回覆:老齊,可查看所有文章、書籍、課程。

覺得好看,就點這裡👇👇👇

相關焦點

  • OpenCV入門及應用案例:手把手教你做DNN圖像分類
    其應用領域橫跨圖像處理、交互式藝術、視頻監督、地圖拼接和高級機器人等。作為一個有十幾年歷史的開源項目,OpenCV擁有廣大的用戶群體和開發者群體。在數字的世界中,一幅圖像由多個點(像素)組成。圖像處理就是對其中一個像素或者一個區域內的像素(塊)進行處理。
  • 「Python+cv2」Python安裝opencv及圖像的基本操作
    如果對Python安裝有疑問的可以參考我的文章:手把手教你搭建Python3開發環境手把手教你安裝python編輯器pycharm2、檢查pip3是否安裝opencv的基本操作1、導入opencv庫import cv22、讀取圖像並顯示圖像讀取並顯示cv2.waitKey
  • 【Python3+OpenCV】實現圖像處理—基本操作篇
    OpenCV是一個C++庫,目前流行的計算機視覺編程庫,用於實時處理計算機視覺方面的問題,它涵蓋了很多計算機視覺領域的模塊。在Python中常使用OpenCV庫實現圖像處理。本文將介紹如何在Python3中使用OpenCV實現對圖像處理的基礎操作:
  • 基於OpenCV的圖像分割處理!
    學習目標算法理論介紹閾值處理threshold函數OpenCV使用threshold函數實現閾值化處理。使用threshold進行閾值處理時,需要自定義一個閾值,並以此閾值作為圖像閾值處理的依據 。所以,在實際應用中,總是將其與其他方法結合起來使用。
  • Python+OpenCV的基礎圖像處理操作匯總
    Python中的OpenCV庫進行圖像處理的一些基本操作。圖像處理是對圖像進行的技術操作與分析,比如為了得到增強的圖像或提取一些有用的信息而進行的一系列操作。隨著我們的發展,許多應用程式使用圖像/幀/視頻作為輸入,對它們進行預處理,並將其輸入到設備或軟體或腳本中。圖像處理也可以是娛樂性的,可以用於許多應用。
  • 基於opencv 的圖像處理入門教程
    前言雖然計算機視覺領域目前基本是以深度學習算法為主,但實際上很多時候對圖片的很多處理方法,並不需要採用深度學習的網絡模型,採用目前成熟的圖像處理庫即可實現,比如 OpenCV 和 PIL ,對圖片進行簡單的調整大小、裁剪、旋轉,或者是對圖片的模糊操作。
  • Python 圖像處理 OpenCV (1):入門
    引言又開一個新的系列分享,對圖像處理感興趣的同學可以關注這個系列。更新頻率儘量保持一周兩到三次推送。
  • 基於 opencv 的圖像處理入門教程
    雖然計算機視覺領域目前基本是以深度學習算法為主,但實際上很多時候對圖片的很多處理方法,並不需要採用深度學習的網絡模型,採用目前成熟的圖像處理庫即可實現,比如 OpenCV 和 PIL ,對圖片進行簡單的調整大小、裁剪、旋轉,或者是對圖片的模糊操作。
  • 使用Python+OpenCV實現神經網絡預處理人臉圖像的快速指南
    這通常意味著需要應用深度學習,因此在將圖像注入到我們的神經網絡之前需要一個特殊的預處理階段。為了提高我們的模型精度,這是一項非常重要的任務,通過以下幾個簡單的步驟可以很好地完成。對於本文,我們使用OpenCV:一個高度優化的計算機視覺開源庫,在C++、java和Python中都可用。這是一篇簡短的文章,包含了一些基本的指導原則、示例和代碼,你可以根據需求將它們應用到人臉分類或識別問題上。
  • 使用Python+OpenCV進行圖像處理之入門教程
    圖像處理有很多種應用,包括用於解析文檔和生成相應文本的光學字符識別(OCR)、圖像增強與重建、物體識別、人體運動識別、手勢識別、人臉識別等。在學習的過程中,你會遇到過奇形怪狀的各種圖像濾波器,那有沒有去思考如何實現它嗎,在本文中,我們將通過實現一個簡單的濾波器來開始我們的圖像處理之旅!什麼是OpenCVOpenCV是一個開源庫,包含了許多計算機視覺算法。
  • opencv學習—03圖像運算(一)
    在灰度圖像中,像素用8bit(1個字節)來表示,像素值的範圍是[0,255]。兩個像素值進行加法運算時求得的和可能超過255,不同的加法運算對超過255數值的處理方式不一樣。>a + b ≤ 255:cv2.add(a, b) = a+ba + b >255:cv2.add(a, b) = 255注意使用函數cv2.add( )中的參數有以下三種參數形式:cv2.add(圖像1,圖像2):兩個參數都是圖像,但必須保持圖像的大小和類型一致cv2.add
  • 使用Python+OpenCV實現圖像數據採集
    安裝cv2(OpenCV)我們將使用的圖像庫是cv2。因為cv2不能在Kaggle這樣的在線平臺上工作,所以它必須在你的計算機上本地完成。然而,模型的權重仍然可以在Kaggle上進行訓練,以.h5文件的形式下載(基於Keras/TensorFlow)並加載。
  • opencv-python圖像預處理-濾波
    為了消除外界環境對圖像採集的幹擾,增強圖像的邊緣及灰度跳變的部分,使圖像變得清晰以及提高圖像處理速度需要對圖像進行預處理操作,主要是對圖像進行濾波和增強操作。使用的方法可以分為空間域處理和頻率域處理兩類。空間域指圖像平面本身,這類圖像處理方法用各種模板直接與圖像進行卷積運算,實現對圖像的處理。
  • 使用Python OpenCV處理圖像之使用OpenCV獲取並修改圖像的像素值
    前幾篇內容我們學習了使用OpenCV打開顯示、保存圖像的方法使用Python OpenCV處理圖像之圖像文件的打開、顯示和保存操作,我們還使用OpenCV更改了微信頭像一個Pythoner獲取微信國旗頭像的正確途徑,請不要再@微信官方了。
  • 基於OpenCV的實用圖像處理操作
    如果此圖像是彩色的,則此尺寸變為200x200x3(RGB)。實際上,圖像處理中的每個操作都是矩陣運算。假設需要對圖像進行模糊操作。特定的過濾器會在整個矩陣上移動,從而對所有矩陣元素或部分矩陣元素進行更改。作為該過程的結果,圖像的所需部分或全部變得模糊。在許多情況下都需要對圖像進行處理[1]。通常,這些操作應用於將在深度學習模型中使用。例如,使用彩色圖像進行訓練會導致性能下降。
  • OpenCV圖像處理專欄十四 | 基於Retinex成像原理的自動色彩均衡算法(ACE)
    前言這個算法是IPOL上一篇名為《Automatic Color  Equalization(ACE) and its Fast Implementation》提出的,這實際上也是《快速ACE算法及其在圖像拼接中的應用》這篇論文中使用的ACE算法,這個算法主要是基於Retinex成像理論做的自動彩色均衡,我用C++ OpenCV實現了,來分享一下
  • opencv-python獲取圖像:面向對象與面向過程
    這裡需要注意以下,opencv讀取圖片默認通道為BGR的格式,當在其他UI用戶界面顯示圖像時注意轉換一下通道順序,例如BGR轉換成RGB:Image1=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)下面讀取一張圖片並顯示
  • opencv教程-圖像平滑、二值化
    1:圖像平滑圖像平滑也就是模糊處理,去噪處理。這裡我們先來了解以下幾個詞:低頻分量:圖像種亮度/灰度變化比較平緩的部分。低通濾波和高通濾波在圖像中就是用卷積核對圖像進行卷積操作,不同的卷積核會有不同的濾波效果。卷積核是個二維數組,半徑維奇數,比如5*5,7*7等。
  • 【Python3+OpenCV】實現圖像處理—灰度變換篇
    OpenCV是一個C++庫,目前流行的計算機視覺編程庫,用於實時處理計算機視覺方面的問題,它涵蓋了很多計算機視覺領域的模塊。在Python中常使用OpenCV庫實現圖像處理。本文將介紹如何在Python3中使用OpenCV實現對圖像處理的灰度變換:灰度化處理,二值化處理,伽馬變換,對數變換,反向變換
  • 使用Python OpenCV處理圖像之詳解使用OpenCV處理鍵盤滑鼠事件
    你真的不知道麼?使用Python OpenCV處理圖像之圖像文件的打開、顯示和保存操作中,我們使用OpenCV打開顯示並保存了一幅圖像。那麼問題來了,如果我們需要在圖像打開顯示時,檢測滑鼠的輸入並執行相應的函數,應該怎麼做呢?cv2的處理機制是怎樣的呢?滑鼠響應事件具體如何描述呢?今天,我們來詳細了解下。