訂閱
糾錯
加入自媒體

一文教你使用HSV顏色模型和openCV構(gòu)建晝夜分類器

在本文中,我們將學(xué)習(xí)如何構(gòu)建一個簡單的模型,它使用色調(diào)飽和度值 (HSV) 顏色模型作為特征提取,opencv 進(jìn)行圖像處理的基礎(chǔ)來對白天和黑夜進(jìn)行分類。

介紹

色調(diào)飽和度值(HSV)是RGB的替代顏色模型。色調(diào)(H)是顏色輪中的三種主色和三種次色。飽和度是顏色的純度和強度,其越低,顏色越接近灰色。值 (V) 是指顏色的相對亮度或暗度。這些值中的每一個都有一個限制;H 從 0 到 360,S 和 V 從 0 到 100。

我們將利用顏色模型的 Value (V) 屬性。決定圖像亮度的圖像值 (V)。這是我們要提取的特征。然后我們將設(shè)置一個閾值,可以將白天圖像與夜間圖像分開。

雖然我們可以設(shè)置一個特定的閾值,但我們嘗試使用訓(xùn)練圖像,通過基本推導(dǎo)找到一個最佳閾值。

我們將使用 opencv 庫從圖像中提取這些特征。

先決條件

  1. Python
  2. pip
  3. opencv
  4. numpy
  5. matplotlib

Opencv 是一個計算機視覺包,我們將使用它來處理圖像和操作它。numpy用于數(shù)值計算,matplotlib用于圖像顯示。

1. 導(dǎo)入用于測試的庫和圖像

我們將使用的是用于訓(xùn)練和測試的室外圖像

該圖像已被標(biāo)注,即分類為白天和夜間圖像。

from util import daynight_helper
import matplotlib.pyplot as plt
import cv2
import numpy as np
#path to the folder where the images are
training_data_path = 'data/day_night_images/training'

2. 預(yù)處理圖像及其標(biāo)簽

我們已經(jīng)指定了訓(xùn)練圖像的路徑,但原始圖像有噪聲并且沒有很好地優(yōu)化分析。

例如,圖像可能具有不同的大小,或者標(biāo)簽可能是我們的文字。這是設(shè)計模型的第一步。數(shù)據(jù)清洗。所以我們會寫一個助手來幫助我們。

這是我們的圖像文件夾結(jié)構(gòu)的樣子

data / 
 day_night_images /
   training /
     day /
       img001.jpg
       img002.jpg
     night /
       img100.jpg
       img101.jpg
   test /
     day /
       img001.jpg
       img002.jpg
     night /
       img100.jpg
       img101.jpg

因此,我們希望我們的助手讀取這個目錄并輸出帶有相應(yīng)標(biāo)簽的圖像,以便img001.jpg有一個日期標(biāo)簽。

我們還將使用數(shù)字對標(biāo)簽進(jìn)行編碼。1代表白天,0代表夜晚。

這是代碼:

import os
import glob
import matplotlib.image as mpimg
import cv2
def load_dataset(image_dir):
   img_list = []
   img_types = ['day', 'night']
   
   for img_type in img_types:
       
       for file in glob.glob(os.path.join(image_dir, img_type, '*')):
           img = mpimg.imread(file)
           
           if not img is None:
               img_list.a(chǎn)ppend((img, img_type))
               
   
   return img_list
def standardize_image(image):
   std_img=  cv2.resize(image, (1110, 600))  
   return std_img
def encode_label(label):
   if label== 'day':
       return 1
   else:
       return 0
def standardize_inputs(img_list):
   std_list = []
   
   for img in img_list:
       std_img = standardize_image(img[0])
       std_label = encode_label(img[1])
       
       std_list.a(chǎn)ppend((std_img, std_label))
   
   return std_list      

第 8-18 行負(fù)責(zé)檢查文件夾中的所有圖像,如果是圖像,則將其添加到列表img_list

第 24 行是我們標(biāo)準(zhǔn)化圖像的地方,在這種特殊情況下,我們將其大小調(diào)整為 1110 x 600

第 28 -32 行是我們將標(biāo)簽從文本編碼為數(shù)字的地方。如果是白天,則為1,否則 0

第 34-43 行是我們從第 8 行創(chuàng)建的列表,對圖像進(jìn)行標(biāo)準(zhǔn)化并對標(biāo)簽進(jìn)行編碼。

讓我們在我們的項目中導(dǎo)入它并運行以下代碼以查看是否設(shè)置了助手程序。

training_data_path = 'data/day_night_images/training'
training_data = daynight_helper.load_dataset(training_data_path)
std_training_data = daynight_helper.standardize_inputs(training_data)
img = std_training_data[0][0]
label = std_training_data[0][1]
plt.imshow(img)
print('Shape ', img.shape)
print('label: ', label)

這應(yīng)該為你提供Shape (600, 1110, 3) 標(biāo)簽的輸出:1

3.獲取圖片的平均亮度

接下來,我們將編寫一個函數(shù)(基于 HSV 顏色模型)來獲取圖像的平均亮度。因此,這個分類問題的特征是亮度。我們正在提取并使用它來解釋新圖像。

#feature extraction - brightness using hsv
def brightness_value(img):
   hsv_img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
   v_values = np.sum(hsv_img[:, :, 2])
   area = img.shape[0] * img.shape[1]
   avg_brightness = v_values/area
   return avg_brightness

基本上,我們選擇 HSV 顏色模型的 V 值并將其除以圖像面積。

在示例圖像上運行此函數(shù)以了解圖片的亮度。

4. 使用選定的標(biāo)記晝夜差異的閾值來估計標(biāo)簽

一旦我們獲得了圖片的平均亮度,我們就可以標(biāo)記一個閾值來劃分白天和夜晚的圖片。

這個標(biāo)志著晝夜的差異是我們最大的盟友。請記住,閾值是平均亮度的函數(shù)。

這是預(yù)測標(biāo)簽的代碼:

def estimate_label(img, threshold):
   avg_brightness = brightness_value(img)
   predicted_label = 0
   threshold = threshold
   if avg_brightness > threshold:
       predicted_label = 1
   
   return predicted_label, avg_brightness

很簡單吧?

但是我們怎么知道閾值呢?

答案:我們在計算了一些白天和黑夜圖像的平均亮度后進(jìn)行選擇,然后我們從中做出直觀的猜測。

這是我們的出發(fā)點。對于這種情況,我們選擇 120。

但是 120 是最佳閾值嗎?

5. 尋找最優(yōu)閾值

我們可以在閾值為 120 時結(jié)束我們的模型預(yù)測,我們的準(zhǔn)確率為 86%。但是,我們是否可以通過調(diào)整或修改閾值來提高準(zhǔn)確度,以接近在白天和黑夜之間劃出細(xì)線的那個點——比如白天和黑夜本身。

因此看看優(yōu)化器代碼:

def estimate_label(img, threshold):
   avg_brightness = brightness_value(img)
   predicted_label = 0
   threshold = threshold
   if avg_brightness > threshold:
       predicted_label = 1
   
   return predicted_label, avg_brightness

在這里,我們根據(jù)閾值估計標(biāo)簽,如果它是正確的,我們就接著下一步。

如果不是,我們計算當(dāng)前閾值和平均亮度的平均值——因為閾值是基于平均亮度的。

threshold = 120
for i in range(0, len(std_training_data)):
   img_data = std_training_data[i]
   threshold = optimize_threshold(img_data, threshold)
print('threshold ', threshold)
#threshold  116

運行這個會產(chǎn)生一個新的閾值——116。

PS:可以以不同的方式調(diào)整閾值,即平均閾值和平均亮度。這是我在這段代碼中使用的技術(shù)。

6. 在測試圖像上運行分類器

我們有我們的閾值和估算器。讓我們在測試圖像上運行我們的模型,看看表現(xiàn)如何。

import random
test_data_path = 'data/day_night_images/test'
test_data = daynight_helper.load_dataset(test_data_path)
test_data = daynight_helper.standardize_inputs(test_data)
random.shuffle(test_data)
threshold = 116
correctly_classified = []
misclassified = []
for i in range(0, len(test_data)):
   img_data = test_data[i]
   pred, avg_brightness = estimate_label(img_data[0], threshold)
   #print('predicted ', pred)
   label = img_data[1]
   #print('label ', label)
   if pred == label:
       correctly_classified.a(chǎn)ppend(img_data)
   else:
       misclassified.a(chǎn)ppend(img_data)
       
#total :  160
#Correct predictions:  140
#Misclassified:  20
#Accuracy  0.875

我們從清理我們的測試數(shù)據(jù)開始,然后對其進(jìn)行打亂(第 7 行)。因為我們已經(jīng)有了閾值。我們可以估計標(biāo)簽。然后記錄輸出——正確分類與否。

與僅選擇 120 作為閾值時的 86% 相比,我們對此的準(zhǔn)確率為 87.5%。而且還有改進(jìn)的空間。

思考。還可以做些什么來進(jìn)一步提高準(zhǔn)確性?你能否添加另一個功能來跟蹤平均亮度?有沒有辦法將閾值移動到最佳值?

聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯
x
*文字標(biāo)題:
*糾錯內(nèi)容:
聯(lián)系郵箱:
*驗 證 碼:

粵公網(wǎng)安備 44030502002758號