2024-09-12|閱讀時間 ‧ 約 10 分鐘

[OpenCV][Python]利用連通域分析來過濾雜點

先前文章有使用連通域分析來印出物件的位置及高寬面積及達成物件定位等功能。

[OpenCV應用][Python]利用連通域分析達成物件定位

[OpenCV基礎][Python]connectedComponent連通域分析

[OpenCV][Python]印出圖像中OCR面積及位置

這次我們將利用它來達成過濾掉不重要的雜點,在先前的文章中有利用OpenCV找輪廓的方式來濾除,這一次我們利用連通域分析來設定更多條件濾除。

[OpenCV基礎][Python]遮罩,旋轉,輪廓應用濾除斑點

先上結果圖

左邊是原圖有一推雜點跟痕跡,右邊是我們設定條件濾除掉的結果。只保留想檢測OCR的部分。


程式範例

import cv2
import numpy as np

def __connectorFileter(binaryImg: np.array , obj_Spec: tuple) -> np.array:
'''
binaryImg : 輸入的二值化圖像,僅包含0255的值。
obj_Spec :
obj_Spec: tuple:一個元組,用來定義要過濾物件的規格
WidthMax:物件的最大寬度
HeightMin:物件的最小高度
HeightMax:物件的最大高度
AreaMin:物件的最小面積
'''
WidthMin,WidthMax,HeightMin,HeightMax,AreaMin = obj_Spec
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binaryImg, connectivity=8)

imgH, imgW = binaryImg.shape
obj = set()
objLoc = {}

# 移除雜訊區塊
if True:
for i in range(len(stats)): #x, y, w, h = stats[i][:4]
# 排除法
# 物件座標
if stats[i][0] == 0 or stats[i][1] == 0:
continue
# 物件邊界
if stats[i][0] + stats[i][2] >= imgW or stats[i][1] + stats[i][3] >= imgH:
continue
# 物件寬度
if stats[i][2] < WidthMin or stats[i][2] > WidthMax:
continue
# 物件高度
if stats[i][3] < HeightMin or stats[i][3] >= HeightMax:
continue
# 物件面積
if stats[i][4] <= AreaMin:
continue
objLoc[i] = (stats[i][0], stats[i][1], stats[i][2], stats[i][3])

# 移除字母內的瑕疵
for i in obj:
noise = False
left_i = objLoc[i][0]
right_i = objLoc[i][0]+ objLoc[i][2]
top_i = objLoc[i][1]
bottom_i = objLoc[i][1]+objLoc[i][3]
for j in objLoc:
left_j = objLoc[j][0]
right_j = objLoc[j][0]+ objLoc[j][2]
top_j = objLoc[j][1]
bottom_j = objLoc[j][1]+objLoc[j][3]
if i != j and left_j < left_i and right_i< right_j and top_j< top_i and bottom_i < bottom_j:
noise = True
break
if not noise:
obj.add(i)

# 字母保留區塊
for i in range(num_labels):
if i in letters:
labels[labels == i] = True
else:
labels[labels == i] = False
# convert to binary image
labels[labels>0]=255
labels[labels==0]=0
labels = np.array(labels, dtype='uint8')

return labels

if __name__ == "__main__" :
# 讀取圖檔
imgpath ='F:/python/opencv/chars_training_dirty.png'
img = cv2.imdecode(np.fromfile(file=imgpath, dtype=np.uint8), cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Otsu's 方法進行自動二值化
threshold_img = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# 需讓OCR轉換成白色字體才能用連通域分析
threshold_img = 255 - threshold_img

#設定過濾條件
Filete_spec = (10,100,10,100,200)
Fileter_img = __connectorFileter(threshold_img,Filete_spec)

#顯示結果圖
cv2.imshow('Orignal_img',threshold_img)
cv2.imshow('Fileter_img',Fileter_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


__connectorFileter 函式的關鍵步驟:

  1. cv2.connectedComponentsWithStats
    這個函式用來標記二值影像中的連通區域,並返回四個值:
    • num_labels:標記的連通區域數量。
    • labels:標記圖,每個像素標記屬於哪個連通區域。
    • stats:每個區域的統計資訊,如邊界框(x, y, w, h)和面積。
    • centroids:每個區域的質心。
  2. 雜訊過濾與物件篩選
    使用for迴圈遍歷每個物件,根據以下條件過濾物件:
    • 物件是否靠近影像邊界(排除位於邊界的物件)。
    • 物件的寬度、高度是否在指定範圍內。物件的面積是否大於指定的最小面積。
    • 篩選出的物件會存入objLoc字典,記錄它們的座標和尺寸。
  3. 內部瑕疵移除
    • 檢查物件之間是否有較小的物件完全包裹在另一個較大的物件內部,這些內部的物件視為瑕疵,會被移除。
  4. 物件保留區塊
    • 將符合條件的物件標記為True,其他的標記為False,最後將labels轉換回二值化影像(0和255兩個值)。

函式返回:

  • labels: np.array:最後經過處理的二值化影像,其中保留了符合規格的物件,移除了雜訊和瑕疵。

其他要點:

  • set():用來儲存符合條件的物件索引。
  • 物件座標檢查:會透過邊界(寬高、座標)及面積條件進行嚴格的過濾,避免雜訊影響分析結果。


分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.