樹莓派+python+opencv(對象追蹤,幾何變換,閾值,圖像模糊)

一:更改色彩空間(一共150多種)
對於顏色轉換,我們使用函數cv2.cvtColor(input_image,flag),其中flag確定轉換類型。
對於BGR Gray轉換,我們使用標誌cv2.COLOR_BGR2GRAY。類似地,對於BGR HSV,我們使用標誌cv2.COLOR_BGR2HSV。要獲取其他標誌,只需在Python終端中運行以下命令:→→

 import cv2
flags = [c for c in dir(cv2) if c.startswith('COLOR_')]
print (flags)

在這裏插入圖片描述

二:對象追蹤
• 拍攝視頻的每一幀
• 從BGR轉換爲HSV色彩空間
• 我們將HSV圖像閾值爲一系列藍色
• 現在單獨提取藍色對象,我們可以對我們想要的圖像做任何事情。

import cv2
#flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
#print (flags)
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
#拍攝每一幀
    _,frame = cap.read()
#將BGR轉換爲HSV
    hsv = cv2.cvtColor (frame,cv2.COLOR_BGR2HSV)
#defn定義HSV中的藍色範圍
    lower_blue = np.array ([110,50,50])
    upper_blue = np.array ([120,255,255])
#閾值HSV圖像僅獲得藍色
    mask = cv2.inRange (hsv, lower_blue, upper_blue)
#Bitwise-AND掩碼和原始圖像
    res = cv2.bitwise_and (frame, frame, mask = mask)
    cv2.imshow ('frame',frame)
    cv2.imshow('mask',mask)
    cv2.imshow('res',res)
    k = cv2.waitKey (5) & 0xFF
    if k ==27:
        break
cv2.destroyAllWindows()
 

在這裏插入圖片描述
三:圖像的幾何變換
轉換提供了兩個轉換函數cv2.warpAffine和cv2.warpPerspective,其中cv2.warpAffine採用2x3變換矩陣,而cv2.warpPerspective採用3x3變換矩陣作爲輸入。
縮放 調整圖像大小,cv2.resize(), 優選的內插方法是cv2.INTER_AREA用於收縮和cv2.INTER_CUBIC(慢)cv2.INTER_LINEAR用於變焦。默認情況下,使用的插值方法是cv2.INTER_LINEAR,用於所有調整大小的目的
旋轉

在這裏插入圖片描述

import numpy as np
import cv2
def main():
    img = cv2.imread('.\\imgs\\img10.jpg')
    height, width = img.shape[:2]
 
    matRotate = cv2.getRotationMatrix2D((height * 0.5, width * 0.5), -90, 1)
    dst = cv2.warpAffine(img, matRotate, (width, height*2))
    rows, cols = dst.shape[:2]
 
    for col in range(0, cols):
        if dst[:, col].any():
            left = col
            break
 
    for col in range(cols-1, 0, -1):
        if dst[:, col].any():
            right = col
            break
 
    for row in range(0, rows):
        if dst[row,:].any():
            up = row
            break
 
    for row in range(rows-1,0,-1):
        if dst[row,:].any():
            down = row
            break
 
    res_widths = abs(right - left)
    res_heights = abs(down - up)
    res = np.zeros([res_heights ,res_widths, 3], np.uint8)
 
    for res_width in range(res_widths):
        for res_height in range(res_heights):
            res[res_height, res_width] = dst[up+res_height, left+res_width]
 
    cv2.imshow('res',res)
 
    cv2.imshow('img',img)
    cv2.imshow('dst', dst)
    cv2.waitKey(0)
 
if __name__ =='__main__':
    main()
 

在這裏插入圖片描述

四。圖像的閾值
閾值就是最簡單的圖像的分割法
1.簡單的閾值(如果像素值大於閾值,則爲其分配一個值(可以是白色),否則爲其分配另一個值(可以是黑色)
cv2.threshold(源圖像也就是灰度圖像,對像素值進行分類的閾值,maxVal表示如果像素值大於(有時小於)閾值則要給出的值)
ret, dst = threshold(src, thresh, maxval, type)
ret: retVal(返回值),在Otsu‘s中會用到
dst: 目標圖像
src: 原圖像,只能輸入單通道圖像,通常來說爲灰度圖
thresh: 閾值
maxval: 當像素值超過了閾值(或者小於閾值,根據type來決定),所賦予的值
type:閾值類型,包含以下5種類型:1.二進制閾值化:cv2.THRESH_BINARY ,大於閾值取maxval,小於取0
2.反二進制閾值化:cv2.THRESH_BINARY_INV ,大於閾值取0,小於取maxval
3.截斷閾值化:cv2.THRESH_TRUNC ,大於閾值全取閾值大小,小於則不變
4.閾值化0:cv2.THRESH_TOZERO ,大於閾值取原值,小於取0
5.反閾值化0:cv2.THRESH_TOZERO_INV ,大於閾值取0,小於取原值

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

直接拿代碼

import cv2
import numpy as np
from matplotlib import pyplot as plt
 
img = cv2.imread('/home/pi/Desktop/opencv/123.jpg', 0)
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
    plt.subplot(2, 3, i+1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

以爲沒問題,但出現了以下問題
在這裏插入圖片描述
庫中沒有matplotlib函數,然後我百度了一下,網上一種方法是
在這裏插入圖片描述
但是還是出現了同樣的問題,然後我找到了另一個方法
直接安裝: sudo apt-get install python3-matplotlib
ok,成功了,可以運行了
在這裏插入圖片描述
2.自適應閾值
cv2.adaptiveThreshold(src, maxVal, adaptiveMethold, thresholdType, blockSize, C, dst)
src: 原圖像,只能輸入單通道圖像,通常來說爲灰度圖
maxval: 當像素值超過了閾值(或者小於閾值,根據type來決定),所賦予的值
thresholdType:二值化操作的類型,與固定閾值函數相同,包含5種類型,同上一節。
blockSize: 圖片中分塊的大小
C :閾值計算方法中的常數項
dst:目標圖像
adaptiveMethold: 閾值的計算方法,包含以下2種類型:
cv2.ADAPTIVE_THRESH_MEAN_C, 閾值取自相鄰區域的平均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 閾值取值相鄰區域的加權和,權重爲一個高斯窗口

import cv2
import numpy as np
from matplotlib import pyplot as plt
 
img = cv2.imread('/home/pi/Desktop/opencv/123.jpg', 0)
img = cv2.medianBlur(img, 5) # 中值濾波
 
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 11 爲 Block size, 2 爲 C 值
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
titles = ['Original Image',
          'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2, 2, i+1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在這裏插入圖片描述
在這裏插入圖片描述

3.Otsu’s二值化
Otsu’s Binarization是一種基於直方圖的二值化方法,它需要和threshold函數配合使用
在第一部分中我們提到過 retVal,當我們使用 Otsu 二值化時會用到它。 那麼它到底是什麼呢? 在使用全局閾值時,我們就是隨便給了一個數來做閾值,那我們怎麼知道
我們選取的這個數的好壞呢?答案就是不停的嘗試。如果是一副雙峯圖像(簡 單來說雙峯圖像是指圖像直方圖中存在兩個峯)呢?我們豈不是應該在兩個峯之間的峯谷選一個值作爲閾值?這就是 Otsu 二值化要做的。簡單來說就是對 一副雙峯圖像自動根據其直方圖計算出一個閾值。(對於非雙峯圖像,這種方法 得到的結果可能會不理想)。 這裏用到到的函數還是cv2.threshold(),但是需要多傳入一個參數flag:cv2.THRESH_OTSU。這時要把閾值設爲 0。然後算法會找到最優閾值,這個最優閾值就是返回值 retVal。如果不使用 Otsu 二值化,返回的 retVal 值與設定的閾值相等。
Otsu過程:

  1. 計算圖像直方圖;
  2. 設定一閾值,把直方圖強度大於閾值的像素分成一組,把小於閾值的像素分成另外一組;
  3. 分別計算兩組內的偏移數,並把偏移數相加;
  4. 把0~255依照順序多爲閾值,重複1-3的步驟,直到得到最小偏移數,其所對應的值即爲結果閾值。
import cv2
import numpy as np
from matplotlib import pyplot as plt
 
img = cv2.imread('/home/pi/Desktop/opencv/123.jpg', 0)
# global thresholding
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
# (9,9)爲高斯核的大小,8 爲標準差
blur = cv2.GaussianBlur(img, (9, 9), 8)
# 閾值一定要設爲 0!
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1, img, 0, th2, blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)', 'Original Noisy Image',
          'Histogram', "Otsu's Thresholding", 'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
# 這裏使用了 pyplot 中畫直方圖的方法,plt.hist, 要注意的是它的參數是一維數組
# 所以這裏使用了(numpy)ravel 方法,將多維數組轉換成一維,也可以使用 flatten 方法
# ndarray.flat 1-D iterator over an array.
# ndarray.flatten 1-D array copy of the elements of an array in row-major order
for i in range(3):
    plt.subplot(3, 3, i*3+1), plt.imshow(images[i*3], 'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i*3+2), plt.hist(images[i*3].ravel(), 256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i*3+3), plt.imshow(images[i*3+2], 'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
 

在這裏插入圖片描述
五:平滑圖像(圖像模糊)
模糊是卷積的一種表現
1.2D卷積
在這裏插入圖片描述
dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
src 原圖像
dst 目標圖像,與原圖像尺寸和通過數相同
ddepth 目標圖像的所需深度
kernel 卷積核(或相當於相關核),單通道浮點矩陣;如果要將不同的內核應用於不同的通道,請使用拆分將圖像拆分爲單獨的顏色平面,然後單獨處理它們。
anchor 內核的錨點,指示內核中過濾點的相對位置;錨應位於內核中;默認值(-1,-1)表示錨位於內核中心。
detal 在將它們存儲在dst中之前,將可選值添加到已過濾的像素中。類似於偏置。
borderType 像素外推法

import cv2
import numpy as np
ferom matplotlib import pyplot as plt
img = cv2.imread('/home/pi/Desktop/opencv/123.jpg')
kernel = np.ones((5,5),np.float32)/ 25
dst = cv2.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]),plt.yticks([])
plt.show()

在這裏插入圖片描述

2.均值模糊

import cv2  as  cv
import numpy as np
def blur_demo(image):
     dst = cv.blur(image,(1,15))
     cv.imshow("blur_demo", dst)
 
print ("--------Hello Python---------")
src =cv.imread("/home/pi/Desktop/opencv/123.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
blur_demo(src)
cv.waitKey(0)
cv.destroyAllWindow()

在這裏插入圖片描述

拓展:高斯模糊

import cv2 as cv
import numpy as np
 
 
def clamp(pv):
if pv >255:
return 255
if pv <0:
return 0
else:
return pv
 
def gaussian_noise(image):
h,w,c = image.shape
for row in range(h):
for col in range(w):
s = np.random.normal(0 , 20, 3)
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
image[row, col, 0] = clamp(b +s[0])
image[row, col, 1] = clamp(g +s[1])
image[row, col, 2] = clamp(r +s[2])
cv.imshow("noise image", image)
 
print("------Hello Python-------")
src = cv.imread("/home/pi/Desktop/opencv/123.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
gaussian_noise(src)
cv.waitKey(0)
  
cv.destroyAllWindow()

在這裏插入圖片描述

發現有點慢(一開始以爲出錯了)等了一會就出現了
在這裏插入圖片描述
然後加了一個計算消耗時間的函數
在這裏插入圖片描述
3.中值模糊

import cv2  as  cv
import numpy as np
def median_demo(image):
     dst = cv.medianBlur(image,(1,15))
     cv.imshow("blur_demo", dst)
 
print ("--------Hello Python---------")
src =cv.imread("/home/pi/Desktop/opencv/123.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
median_demo(src)
cv.waitKey(0)
cv.destroyAllWindow()

在這裏插入圖片描述
在這裏插入圖片描述

4.卷積的自定義

import cv2
import numpy as np
 
def solve():
 
    src = cv2.imread("./Pictures/car001.jpg")
    if src is None:
        return -1
 
    kernel = np.array((
        [0, -1 0],                                                   
        [-1,5,-1],
        [0,-1,0]), dtype="float32")
改變以上三行的數字實現自定義
 
    dst = cv2.filter2D(src, -1, kernel)
    htich = np.hstack((src, dst))
    cv2.imwrite("./Pictures/car.jpg", htich)
    cv2.imshow('merged_img', htich)
    cv2.waitKey(0)
 
    return 0
 
 
if __name__ == "__main__":
    solve()

在這裏插入圖片描述

參見: https://www.cnblogs.com/lfri/p/10599420.html
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章