首頁>技術>

引言

在本系列文章中,我將使用 Python 的 OpenCV 庫展示一些計算機視覺初學者級別問題的解決方案。

OpenCV 庫是最著名的開源計算機視覺庫,可以用於許多程式語言中。利用它,我們可以對數字影象進行幾何變換、濾波、攝像機標定、特徵提取、目標檢測等修改。

畫素處理

對於第一個問題,作為“ hello world”型別的問題,我們將訪問一個影象並操作其畫素。

首先匯入庫。

import cv2

要載入影象,我們使用 imread 函式作為引數傳遞要讀取的檔案的名稱以及我們希望如何讀取它: 0-Black and White,1-Color,-1-changed。對於這個問題,我們只能解讀為黑白和彩色。為了顯示與讀取類似的影象,我們呼叫一個函式作為引數傳遞要顯示的視窗的名稱及其內容,通常是透過呼叫 imread 建立的影象物件。

因此,讓我們讀取一個黑白影象,訪問它的畫素,改變一些,並顯示結果。影象載入為一個矩陣(每個元素一個畫素) ,如果灰度矩陣有兩個維度,每個元素代表灰度的強度。如果是彩色的,則是一組三個矩陣表示的顏色通道 RGB。

image = cv2.imread("lenna.png", 0)for i in range(200, 210):  for j in range(10, 200):      image[i][j] = 0      cv2.imshow("image", image)

重要提示: 在 OpenCV 中,矩陣的座標是不同的。水平座標為 y,垂直座標為 x。此外,左上角是(0,0)原點的位置。所以座標從左上角向右下方向增長。為了更容易理解,當使用稱為 x 和 y 的變數在座標上迴圈時,我們只會在訪問位置時更改 OpenCV 符號。

讀取之後,我們可以做一些簡單的矩陣訪問和改變畫素顏色我們想要的。在修改了一些之後,我們用一種方法制作了一個矩形,把結果顯示為黑色。

這裡需要一個非常有用的命令,這樣我們就可以使用相同的程式碼對影象進行多個操作。waitKey 等待使用者按下一個鍵繼續執行程式碼(這樣我們就可以看到平靜地顯示的結果)。引數0等待要按的任何鍵在程式碼上繼續。經過這個處理之後,我們再次讀取 Lenna 的影象,但是這一次著色並繪製一個紅色矩形,就像我們之前所做的那樣。

cv2.waitKey(0)image = cv2.imread("lenna.png", 1)for i in range (200,210):    for j in range(10,200):        image[i, j] = [0, 0, 255]cv2.imshow("janela", image)cv2.waitKey(0) cv2.destroyAllWindows()

對於有顏色的影象,畫素訪問的方式是不同的,我們傳遞給畫素的陣列以 BGR 順序表示顏色通道(由於某種“歷史”原因被翻轉過來)。作為輸出,我們有一個最大的亮紅色矩形,建立在同一點。

最後,為了破壞為顯示影象而建立的視窗,我們呼叫了 destroyAllWindows 函式,因此在程式停止執行後什麼也不顯示。

現在,讓我們用黑白影象的底片做一個矩形。矩形的位置由使用者表示,負面效果是從畫素的最大可能值減去畫素(這裡是8 bit:255)。

import cv2, sysimage = cv2.imread("lenna.png", 0)for i in range(int(sys.argv[1]),int(sys.argv[2])):    for j in range(int(sys.argv[3]),int(sys.argv[4])):        image[i][j] = 255 - image[i][j] cv2.imshow("janela", image)    cv2.waitKey(0)cv2.destroyAllWindows()

座標100,200,30,150

進一步探索畫素操作,讓我們重新排列影象的四個象限。四分之一象限表示正方形格式的影象的1/4,就好像影象是在垂直和水平方向上被切成兩半。

對於這個挑戰,我們將使用 Numpy 庫來簡化使用矩陣的操作。Numpy 函式將矩陣分割為給定位置和給定方向。在分割影象之後,我們必須將這些部分以翻轉的順序連線起來。

import cv2import numpy as npimage = cv2.imread("lenna.png", 0)height, width = image.shape#position to be splitted in half of the vertical and 0 for horizontal[h,w] = np.split(image, [int(height/2)], 0)#concatenate flipped in horizontal image = np.concatenate((w,h))#position to be splitted in half of the hoizontal and 1 for vertical [h,w] = np.split(image,[int(width/2)], 1)#concatenate flipped in vertical image = np.concatenate((w,h),1)cv2.imshow("image",image)cv2.waitKey(0)cv2.destroyAllWindows()

填充區域

在計算機視覺中,一個非常常見的任務是計算被檢測場景中的目標。感知物件是檢測屬於每個物件的畫素聚集的必要條件。為了更好地處理這個問題,我們將使用一個二進位制圖片(只有灰度畫素0和255)意味著0黑色背景和1個物件畫素。

這裡我們假設每個白色畫素的聚合都是一個單獨的物件。所以,一個可能的做法是貼標籤。通常標記演算法以二值影象作為輸入,並返回多尺度灰度影象。為此,我們將使用一種內建的演算法來填充被稱為“洪水填充”的區域。該演算法實質上是以種子畫素作為參考,搜尋具有相同顏色的鄰居。如果我們給出一個顏色作為引數的函式使所有的畫素搜尋找到的顏色。

Opencv 中的 floodFill 請求獲得影象、掩碼(not used = None)、種子畫素以及為種子和類似鄰居著色的顏色。有了這個,我們只需要逐個畫素檢查它的顏色,如果是白色,我們改變一些灰色,然後增加灰色,這樣下一個物件將有一個不同的灰度。隨著這個過程的進行,我們可以計算 floodFill 應用了多少次,並假設這是場景中物件的數量。

import cv2image = cv2.imread("bolhas.png",0)height, width = image.shapecv2.imshow("image", image)cv2.waitKey(0)nelem = 0for x in range(height):    for y in range(width):        if image[x,y] == 255:            nelem += 1            cv2.floodFill(image, None, (y,x), nelem)print("Number of elements: ", nelem)cv2.imshow("image", image)cv2.waitKey(0)

結果,我們看不到一些物體,因為使用的灰色縮放是同樣的變數用來計數物件的數量,所以使它成為一個非常深灰色。

由於我們使用灰度來計算物件的數量,因此在一個場景中進行8位處理時,我們會受到場景中255個物件數量的限制。您可以想出不同的方法來解決這個問題,我建議建立另一個變數,當元素數量達到256時(從0開始)跟蹤這個變數。當這種情況發生時,這個變數將遞增,nelem 將為零,以便重新開始。在標籤的最後,我們會得到同樣灰色的物體,但是與 nelem 一起跟蹤的變數可以計算出超過極限後檢測到的物體的數量。

現在再次看到原始的二進位制圖片,我們可以認識到有兩種不同型別的物件,有一個洞和沒有它。我們怎麼能把它們分開計算呢?

首先,我們不知道那些被邊界切開的是否有洞,所以我們忽略它們(以某種方式)。有了場景中的所有物件,解決這個問題的一個方法是在影象的背景中應用 floodFill 為 white 255(如果場景中有超過255個物件,我們必須編輯程式碼來保護最大白色不被使用) ,所以現在我們有了物件灰色縮放,背景白色和黑洞(舊背景) ,因為洪水填充背景白色不會擊中洞。

for x in range(height):    if image[x,0] != 0:        cv2.floodFill(image, None, (0, x),0)    if image[x, width-1] != 0:        cv2.floodFill(image, None, (width-1, x),0)for y in range(width):    if image[0,y] != 0:        cv2.floodFill(image, None, (y,0),0)    if image[height-1, y] != 0:        cv2.floodFill(image, None, (y, height-1), 0)cv2.imshow("image", image)cv2.waitKey(0)

有了這個,我們就解決了這個問題,讓黑洞變成黑色,就是在整個影象中搜索黑色畫素,每找到一個黑色畫素,我們就增加黑洞的數量,然後用洪水填充,這樣我們就不會錯誤地得到和。對於這個例子,我們使用相同的背景顏色,所以我們有洞的感覺。

cv2.floodFill(image, None, (0,0), 255)nHoles = 0for x in range(height):    for y in range(width):        if image[x,y] == 0:            cv2.floodFill(image, None, (y,x), 255)            nHoles += 1print("Number of holes: ", nHoles)cv2.imshow("image", image)cv2.waitKey(0)cv2.destroyAllWindows()

· END ·

20
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Mycat中介軟體發起人,再出神著編寫架構解密從分散式到微服務