# OpenCV ## 介紹 OpenCV 全名是 Open Source Computer Vision Library ( 開源計算機視覺函式庫 ) OpenCV用C++語言編寫,它的主要介面也是C++語言,但是依然保留了大量的C語言介面。該Library也有大量的Python、Java and MATLAB/OCTAVE 的介面。這些語言的API介面函式可以透過線上文件取得。現在也提供對於C#、Ch、Ruby的支援。 ## [影像的色彩轉換](https://steam.oxxostudio.tw/category/python/ai/opencv-cvtcolor.html) 現代顏色系統中使用 8 位(8-bit)來表示顏色的每個通道,包括紅色(R)、綠色(G)和藍色(B)。每個通道使用 8 個位元(bit)來表示,因此每個通道可以表示的可能值有 2^8 = 256 個。 ex: RGB 的色彩模型裡,以 (255,0,0) 表示紅色,但在 HSV 的色彩模型中,紅色則是以 (0,100,100) 來表示,用的色彩模型有: ### 1. RGB 彩色的圖片就是像 Red,Green,Blue合起來組成一個顏色,這三個合起來又稱為是一個RGB的圖片 而在openCV中 顏色的排序是 B G R [B,G,R] Red 0黑~255(最紅),Green 0黑~255(最綠).... ![](https://hackmd.io/_uploads/SJ_5iurLn.png) 1. 圖中channel代表著不同的顏色的數值度 2. 3代表三種顏色,數值則是三種顏色的程度,將三原色光以不同的比例複合後,對人的眼睛可以形成與各種頻率的可見光等效的色覺 3. (像素尺寸)寬、高則代表著是pixel的值 ### 2. RGBA ( 紅、綠、藍、alpha ) RGBA 顏色模型由 RGB 色彩模型和 Alpha 通道組成。alpha 通道為影像的不透明度參數,數值可以用百分比、整數或者使用 0 到 1 的實數表示。例如,若一個像素的 Alpha 通道數值為0% 表示完全透明的 ### 3. 印刷四分色模式(CMYK color model) 顏色減法的方式混和顏色 每種墨水顏色的強度可以在 0 到 100% 的範圍內調整,0% 表示不使用該墨水,而 100% 表示使用全強度的墨水。通過調整這四個通道的墨水強度,可以混合出各種不同的顏色。以下是 CMYK 混色的基本原理: C:Cyan = 吸收紅色,反射青色或「水藍」色。 M:Magenta =吸收綠色,反射 洋紅色或「紫色」。 Y:Yellow =吸收藍色,反射紅色和綠色。 黑色(Key plate)是一種額外的墨水通道,用於調整亮度和對比度,實務上多使用黑色。 ![](https://hackmd.io/_uploads/HJ14yac82.png) ### 4. HSV ( 色相、飽和度、明度 )、HSL ( 色相、飽和度、亮度 ) HSL 和 HSV 顏色模型都是一種將 RGB 色彩模型中的點,轉變在圓柱坐標系中的表示法。 HSL 是色相、飽和度、亮度 ( Hue、Saturation、Lightness ),HSV 是色相、飽和度、明度 ( Hue、Saturation、Value ),又稱 HSB ( Brightness )。 ![](https://hackmd.io/_uploads/SytPTnc82.png) HSL 和 HSV 模型都把顏色描述在圓柱坐標系內的點,這個圓柱的中心軸取值為自底部的黑色到頂部的白色而在它們中間的是灰色,繞這個軸的角度對應於「色相」,到這個軸的距離對應於「飽和度」,而沿著這個軸的高度對應於「亮度」、「色調」或「明度」 ### 5. GRAY ( 灰階 ) 灰階(Grayscale)的圖片是一種只包含灰度色調的圖像,其中所有像素的顏色值在黑色和白色之間。它是一種單色圖像,不包含彩色信息。在灰階圖像中,每個像素的顏色值表示亮度或灰度的程度,可以從純黑色(最暗)到純白色(最亮)之間的不同灰度級別。 ![](https://hackmd.io/_uploads/Hy6S42S8h.png) **位元深度**:每個像素的顏色或亮度值可以使用的位元數量。較高的位元深度意味著每個像素可以表示更多的色彩細節或亮度細節,因此具有更大的色彩範圍或亮度範圍。常見的位元深度有 8 位(256 級灰度或色彩)、16 位(65536 級灰度或色彩)等。 Pixel的定義為:組成點陣數位影像的最小單位,所以又稱作Picture element。每一個小方格都有一個明確的位置與單一的色彩 解析度(Resolution)的定義為:在點陣圖中,「單位長度內像素的數量」;單位是dpi,dpi是英文Dot Per Inch的縮寫,意思是每英寸的畫素點數。 ## opencv讀取影片 圖片 ```python import cv2 img = cv2.imread('color.jpg') img = cv2.resize(img,(0,0),fx=1.5,fy=1.5) ##寬高變1.5倍 cv2.imshow('img',img) # title=img # 將圖像從 BGR 色彩空間轉換為灰階色彩空間 cvtColor 色彩轉換 gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # GaussianBlur 高斯模糊 第一個參數是原始圖像,第二個參數是高斯核的大小,這裡是 (5, 5),表示高斯核的寬度和高度都是 5。第三個參數是標準差,設為 0 表示根據核大小自動計算 blurred_image = cv2.GaussianBlur(img, (5, 5), 0) # 執行Canny邊緣檢測 edges = cv2.Canny(image, 100, 200) # 調整閾值以控制邊緣檢測的結果 cv2.imshow('Blurred Image', blurred_image) cv2.imshow('Canny Edges', edges) #cv2.waitKey(0) #等待按鍵毫秒 0表示無限 ##type(img) -> 格式:numpy ndarray shape ->(height,width,channel) cap = cv2.VideoCaptrue('thumb.mp4') # 抓攝像頭參數:ex:VideoCaptrue(1) 看編號 while True: ret,frame = cap,read() # 取得下一楨bool 取得圖 if ret: frame = cv2.resize(frame,(0,0),fx=0.4,fy=0.4) cv2.imshow('viedo',frame) else: break if cv2.waitKey(1)== ord('q') #每楨等待時間 ord 按按鍵q break ``` ## 圖片的處理 ### 灰階色彩的應用 1. 影像處理:在影像處理中,灰階色彩常用於圖像的預處理和分析。灰階圖像只包含亮度信息,而沒有彩色信息,因此對於許多分析和算法來說更加簡單和高效。 2. 特徵檢測:在許多特徵檢測算法中,首先將彩色圖像轉換為灰階圖像,然後對其進行處理。灰階圖像中的亮度差異更容易檢測和計算,從而幫助識別圖像中的特徵。 3. 圖像分割:在圖像分割中,灰階圖像通常用於區域分割和邊緣檢測。通過分析灰階圖像中的亮度變化,可以識別不同的區域和物體邊界。 4. 表示深度和距離:在一些應用中,例如深度圖像、遙感圖像等,灰階色彩可以用來表示物體的深度、距離或高程。不同的灰階值可以對應到不同的深度或距離範圍。 5. 藝術和攝影:灰階圖像在藝術和攝影中被廣泛使用,可以產生簡約、柔和、純粹的視覺效果。灰階圖像能夠更好地突顯細節、光影和構圖。 ### 高斯模糊 ->第二個參數 高斯核 高斯核的大小通常是一個==奇數==的正整數,例如 (3, 3)、(5, 5)、(7, 7) 等。這個大小決定了模糊效果的程度。較大的核會產生更強烈的模糊效果,而較小的核則會產生較輕微的模糊效果,適用於輕微的模糊或邊緣保留等場景。 在 (n, n) 的高斯核中,n 表示核的寬度和高度。值得注意的是,核的大小必須是正數且奇數,以確保核有一個中心點。 ### Canny 邊緣檢測 Canny邊緣檢測是一種基於閾值的方法,用於檢測圖像中的邊緣。這個方法首先應用一個高斯濾波器來平滑圖像,然後計算圖像的梯度,最後根據梯度值的閾值進行邊緣檢測。 低閾值和高閾值決定了梯度值的範圍,用於區分強邊緣和弱邊緣。通常,低閾值用於檢測可能的邊緣,高閾值用於連接邊緣。在Canny函數中,低閾值和高閾值之間的區域被認為是弱邊緣,高於高閾值的部分被認為是強邊緣。 1. 對圖像應用高斯模糊以減少噪點。 2. 計算圖像中每個像素的梯度強度和方向。 3. 使用高閾值和低閾值將像素劃分為強邊緣、弱邊緣和非邊緣。 4. 通過閾值操作來鎖定邊緣,即將強邊緣視為確定邊緣,將非邊緣排除,並對弱邊緣進行進一步分析以確定是否為邊緣。 ### dilate 膨脹 & erode 侵蝕 當空間中有兩個集合 ( A 集合和 B 集合 ),當 A 集合的部分空間被 B 集合所取代,則稱之為「侵蝕 ( Erosion )」,通常進行侵蝕後的影像,黑色區域會擴張,白色區域會縮小。 當空間中有兩個集合 ( A 集合和 B 集合 ),當 A 集合的部分空間擴張到 B 集合,則稱之為「膨脹 ( Dilation )」,通常進行膨脹後的影像,白色區域會擴張,黑色區域會縮小。 ```python # 讀取圖像 image = cv2.imread('image.jpg') # 建立膨脹核 dilate_kernel = np.ones((5, 5), np.uint8) # 建立侵蝕核 erode_kernel = np.ones((5, 5), np.uint8) # 膨脹圖像 dilated_image = cv2.dilate(image, dilate_kernel, iterations=1) # 侵蝕圖像 eroded_image = cv2.erode(image, erode_kernel, iterations=1) # 顯示原始圖像、膨脹後的圖像和侵蝕後的圖像 cv2.imshow('Original Image', image) cv2.imshow('Dilated Image', dilated_image) cv2.imshow('Eroded Image', eroded_image) cv2.waitKey(0) ``` 下方的程式碼執行後,會先將圖片進行侵蝕,侵蝕後,比較小的白色圓點就會因為侵蝕而消失,接著再進行膨脹,就可以將主體結構恢復原本的大小,實現去除雜訊的效果 ( 恢復原本大小後,邊緣會因為計算的緣故不如原本的銳利 ),這種做法常搭配邊緣偵測、黑白二值化等方法,應用在文字辨識或影像辨識的領域。 ```python import cv2 img = cv2.imread('test.jpg') cv2.imshow('oxxostudio1', img) # 原始影像 img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 11)) img = cv2.erode(img, kernel) # 先侵蝕,將白色小圓點移除 cv2.imshow('oxxostudio2', img) # 侵蝕後的影像 img = cv2.dilate(img, kernel) # 再膨脹,白色小點消失 cv2.imshow('oxxostudio3', img) # 膨脹後的影像 cv2.waitKey(0) # 按下 q 鍵停止 cv2.destroyAllWindows() ``` ![](https://hackmd.io/_uploads/rkMNaIAK3.png) ## 圖形輪廓檢測 findContours 找輪廓、drawContours 畫輪廓、contourArea 輪廓面積、arcLength 輪廓總長、approxPolyDP 近似多邊形、boundingRect 外接矩形 ```python img = cv2.imread('color.jpg') imgContour = img.copy() img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) canny = cv2.Canny(img,150,200) contours, hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) ## RETR_EXTERNAL外輪廓 第三個參數為輪廓的近似方法 函數第一個迴傳的是輪廓 第二個是階層 for cnt in contours: cv2.drawContours(imgContour,cnt,-1,(255,0,0), 4) area = cv2.contourArea(cnt) ##計算輪廓面積 #print(cv2.arcLength(cnt,True)) #輪廓邊長 if area > 500: peri = cv2.arcLength(cnt,True) #計算封閉輪廓的周長 vertices = cv2.approxPolyDP(cnt,peri*0.02, True) #對輪廓進行多邊形逼近,獲取近似的頂點。 corners = len(vertices) x,y,w,h=cv2.boundingRect(vertices) #計算包圍近似多邊形的矩形範圍的左上角坐標和寬度高度。 cv2.rectangle(imgContour,(x,y),(x+w,y+h),(0,255,0),3) if corners ==3: cv2.putText(imgContour,'triangle',(x,y+5),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),2) cv2.imshow('img', img) cv2.imshow('imgContour',imgContour) cv2.waitKey(0) ``` findContours(找輪廓) 函數返回兩個值:輪廓列表和層次結構。 1. 輪廓列表:這是一個包含所有檢測到的輪廓的列表。每個輪廓都表示為一個包含一系列點的NumPy陣列。可以使用這些輪廓進行後續的操作,如 **繪製** 、計算面積、計算周長等。 2. 層次結構:層次結構描述了輪廓之間的層次關係,例如輪廓的父子關係、兄弟關係等。它以層次索引的形式表示,可以使用它來識別輪廓的層次結構。它以一個四元組的形式表示,包含四個整數值 [next, previous, first child, parent] cv2.arcLength() 函數中,第二個參數 closed 是一個布林值,用於指定輪廓是否封閉。 如果 closed 設置為 True,表示輪廓是封閉的,即起點和終點連接在一起形成封閉輪廓。 如果 closed 設置為 False,表示輪廓是開放的,即起點和終點不連接,輪廓線段是開放的。 這個參數的目的是在計算輪廓的周長時,確定是否將起點和終點連接在一起。 cv2.approxPolyDP() 函數中三個參數: 1. curve: 要進行近似的輪廓曲線。 2. epsilon: 輸入曲線到其近似曲線的最大距離。這是一個表示精度的參數。較小的 epsilon 值將產生更接近輪廓的近似曲線。 3. closed: 一個布林值,用於指定輸入曲線是否封閉。 在圖像上繪製文字函數 cv2.putText(img, text, org, fontFace, fontScale, color, thickness) ### 圖像降噪 我們看到很多圖像平滑技術如高斯模糊,Median模糊等,它們在移除數量小的噪音時在某種程度上比較好用。 在這些技術里,我們取圖元周圍的一小部分鄰居,做一些類似於高斯平均權重,中值等替換掉中間的元素。 簡單說,移除一個像素的噪音是基於本地鄰居的。 噪音有一個屬性,噪音一般被認為是具有零平均值的隨機變數。 假設一個像素噪音,p = p0 + n, 其中p0是像素的真實值,n是那個像素的噪音。 你可以從不同圖像取大量的同一個圖元(N)並計算他們的平均值,理想情況下,你應該得到p=p0,因為均值是0. OpenCV提供了這種技術的四種變體。 cv2.fastNlMeansDenoising() - 使用單個灰度圖像 cv2.fastNlMeansDenoisingColored() - 使用彩色圖像。 cv2.fastNlMeansDenoisingMulti() - 用於在短時間內捕獲的圖像序列(灰度圖像) cv2.fastNlMeansDenoisingColoredMulti() - 與上面相同,但用於彩色圖像。 Common arguments: h:參數決定濾波器強度。 較高的h值可以更好地消除雜訊,但也會刪除圖像的細節 (10 is ok) hForColorComponents:與h相同,但僅適用於彩色圖像。 (通常與h相同) templateWindowSize:應該是奇數。 (recommended 7) searchWindowSize:應該是奇數。 (recommended 21) cv2.fastNlMeansDenoisingColored() 如上所述,它用於從彩色圖像中去除雜訊。 (噪音預計是高斯噪音) ```python import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('img.jpg') dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21) plt.subplot(121),plt.imshow(img) plt.subplot(122),plt.imshow(dst) plt.show() ``` ## 人臉偵測 OpenCV 的官方 Github 提供了許多訓練好的特徵模型,下載後就能使用,下載後將 xml 檔案和 Python 的程式檔放在同一層目錄下。 OpenCV 官方 Github:https://github.com/opencv/opencv/tree/4.x/data 人臉特徵模型:[haarcascade_frontalface_default.xml](https://raw.githubusercontent.com/opencv/opencv/4.x/data/haarcascades/haarcascade_frontalface_default.xml) ```python import cv2 cap = cv2.VideoCapture(0) face_cascade = cv2.CascadeClassifier("face_detect.xml") #訓練模型 faces = face_cascade.detectMultiScale(gray) if not cap.isOpened(): print("Cannot open camera") exit() while True: ret, frame = cap.read() if not ret: print("Cannot receive frame") break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 將鏡頭影像轉換成灰階 faces = face_cascade.detectMultiScale(gray) # 偵測人臉 for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) # 標記人臉 cv2.imshow('oxxostudio', frame) if cv2.waitKey(1) == ord('q'): break cap.release() ``` ### detectMultiScale函數的參數 一直使用窗口去偵測人臉,scaleFactor則是每次整張圖做完會將整張圖縮小的比例,minNeighbors則是指需要被偵測圖成功幾次才算是真的人臉 image:要進行檢測的輸入影像。 scaleFactor:檢測窗口的縮放比例,用於在不同尺度下檢測物件。較小的值會提高檢測的精確性,但可能會增加處理時間。 minNeighbors:指定每個候選物件應該保留多少個鄰居。這個參數可以用於排除重疊的檢測結果,較大的值表示需要更多的鄰居才能接受該檢測結果。 minSize:要檢測的物件的最小尺寸。任何小於此尺寸的物件將被忽略。 maxSize:要檢測的物件的最大尺寸。任何大於此尺寸的物件將被忽略。 ## 辨識不同人臉 OpenCV 內建的 LBPH 人臉訓練功能 ( cv2.face.LBPHFaceRecognizer_create()),搭配人臉特徵模型,訓練判斷不同人臉的模型檔案,完成後就能透過攝影機的影像,辨識出不同的人臉,標記出對應的名字。 要使用 cv2.face.LBPHFaceRecognizer_create(),必須先安裝 opencv_contrib_python。 ## YOLO7部屬 YOLO v7相關文章:https://blog.eddie.tw/category/yolo-v7/ 必須先安裝Python:https://blog.eddie.tw/python-install/ 因以下有部分套件不支援Python 3.11.0,所以以下過程會使用舊版的3.10.8 YOLO v7 Github:https://github.com/WongKinYiu/yolov7 ``` 1.git clone https://github.com/WongKinYiu/yolov7 2.下載權重檔,放入yolov7資料夾內 https://github.com/WongKinYiu/yolov7/releases/download/v0.1/yolov7.pt 3.打開CMD,先把調整到YOLO v7的目錄後,輸入以下指令,安裝相關套件 cd yolov7 pip install -r requirements.txt 4.執行指令 python detect.py --weights yolov7.pt --conf 0.25 --img-size 640 --source inference/images/horses.jpg --view-img ``` 網頁 => https://blog.eddie.tw/yolo-v7-install/ ## OCR(光學文字辨識) OCR(Optical Character Recognition)是光學文字辨識的縮寫,透過光學輸入的技術掃描印刷上的文字轉化為圖像,並利用識別技術把圖像中的文字轉換成文本格式。人工智能的應用除了上一篇提及過的語音辨識、影像辨識及自然語言處理外,OCR的智能文字識別亦在社會上廣泛地使用。 OCR的工作步驟能簡單分為五個部分: 影像輸入  OCR是通過各種具光學設備的攝像器材將紙質文檔中的文字轉化為圖像信息。掃描的解像度越高,便對文字識別工作越有利。 影像預處理 由於紙張的印刷質量和掃描儀本身都可能影響文件影像的清晰度,所以在進行文字識別之前,要先清除圖片上的污點。而處理圖像的方法包括版面分析、行字切分、圖像降噪、文字特徵提取等等,來提高OCR的準確性及有效性。 比對識別 OCR的軟體有一套文字的數據庫,當提取文字特徵後,將其特徵與數據庫進行比對識別,然後找出合乎邏輯並且最接近的文字。 ## 參考來源: https://steam.oxxostudio.tw/category/python/ai/opencv-convex-lens.html