基於OpenCV實現對圖片及視訊中感興趣區域顏色識別

2022-07-22 18:01:48

基於OpenCV實現圖片及視訊中選定區域顏色識別

近期,需要實現檢測攝像頭中指定座標區域內的主體顏色,通過查閱大量相關的內容,最終實現程式碼及效果如下,具體的實現步驟在程式碼中都詳細註釋,程式碼還可以進一步優化,但提升有限。

主要實現過程:按不同顏色的取值範圍,對影象進行迴圈遍歷,轉換為灰度圖,將本次遍歷的顏色畫素轉換為白色,對白色部分進行膨脹處理,使其更加連續,計算白色部分外輪廓包圍的面積累加求和,比較每種顏色圍起來面積,儲存最大值及其顏色,所有顏色遍歷完後,返回最大值對應的顏色,顯示在影象上

如果有類似的顏色識別的任務,可參考以下程式碼修改後實現具體需求

colorList.py

import numpy as np
import collections

# 將rgb影象轉換為hsv影象後,確定不同顏色的取值範圍
def getColorList():
    dict = collections.defaultdict(list)

    # black
    lower_black = np.array([0, 0, 0])
    upper_black = np.array([180, 255, 46])
    color_list_black = []
    color_list_black.append(lower_black)
    color_list_black.append(upper_black)
    dict['black'] = color_list_black

    # gray
    lower_gray = np.array([0, 0, 46])
    upper_gray = np.array([180, 43, 220])
    color_list_gray= []
    color_list_gray.append(lower_gray)
    color_list_gray.append(upper_gray)
    dict['gray'] = color_list_gray

    # white
    lower_white = np.array([0, 0, 221])
    upper_white = np.array([180, 30, 255])
    color_list_white = []
    color_list_white.append(lower_white)
    color_list_white.append(upper_white)
    dict['white'] = color_list_white

    # red
    lower_red = np.array([156, 43, 46])
    upper_red = np.array([180, 255, 255])
    color_list_red = []
    color_list_red.append(lower_red)
    color_list_red.append(upper_red)
    dict['red'] = color_list_red

    # red2
    lower_red = np.array([0, 43, 46])
    upper_red = np.array([10, 255, 255])
    color_list_red2 = []
    color_list_red2.append(lower_red)
    color_list_red2.append(upper_red)
    dict['red2'] = color_list_red2

    # orange
    lower_orange = np.array([11, 43, 46])
    upper_orange = np.array([25, 255, 255])
    color_list_orange = []
    color_list_orange.append(lower_orange)
    color_list_orange.append(upper_orange)
    dict['orange'] = color_list_orange

    # yellow
    lower_yellow = np.array([26, 43, 46])
    upper_yellow = np.array([34, 255, 255])
    color_list_yellow = []
    color_list_yellow.append(lower_yellow)
    color_list_yellow.append(upper_yellow)
    dict['yellow'] = color_list_yellow

    # green
    lower_green = np.array([35, 43, 46])
    upper_green = np.array([77, 255, 255])
    color_list_green = []
    color_list_green.append(lower_green)
    color_list_green.append(upper_green)
    dict['green'] = color_list_green

    # cyan
    lower_cyan = np.array([78, 43, 46])
    upper_cyan = np.array([99, 255, 255])
    color_list_cyan = []
    color_list_cyan.append(lower_cyan)
    color_list_cyan.append(upper_cyan)
    dict['cyan'] = color_list_cyan

    # blue
    lower_blue = np.array([100, 43, 46])
    upper_blue = np.array([124, 255, 255])
    color_list_blue = []
    color_list_blue.append(lower_blue)
    color_list_blue.append(upper_blue)
    dict['blue'] = color_list_blue

    # purple
    lower_purple = np.array([125, 43, 46])
    upper_purple = np.array([155, 255, 255])
    color_list_purple = []
    color_list_purple.append(lower_purple)
    color_list_purple.append(upper_purple)
    dict['purple'] = color_list_purple

    return dict

if __name__ == '__main__':
    color_dict = getColorList()
    print(color_dict)

    num = len(color_dict)
    print('num=', num)

    for d in color_dict:
        print('key=', d)
        print('value=', color_dict[d][1])

image_color_realize.py

import cv2
import colorList

# 實現對圖片中目標區域顏色的識別
def get_color(frame):
    print('go in get_color')
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    maxsum = 0
    color = None
    color_dict = colorList.getColorList()

    # count = 0

    for d in color_dict:
        mask = cv2.inRange(hsv, color_dict[d][0], color_dict[d][1])  # 在後兩個引數範圍內的值變成255
        binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)[1]  # 在灰度圖片中,畫素值大於127的都變成255,[1]表示呼叫影象,也就是該函數第二個返回值

        # cv2.imshow("0",binary)
        # cv2.waitKey(0)
        # count+=1

        binary = cv2.dilate(binary, None, iterations=2)  # 使用預設核心進行膨脹操作,操作兩次,使縫隙變小,影象更連續
        cnts = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]  # 獲取該函數倒數第二個返回值輪廓
        sum = 0
        for c in cnts:
            sum += cv2.contourArea(c)  # 獲取該顏色所有輪廓圍成的面積的和
        # print("%s  , %d" %(d, sum ))
        if sum > maxsum:
            maxsum = sum
            color = d
            if color == 'red2':
                color = 'red'
            elif color == 'orange':
                color = 'yellow'
            elif color == 'purple' or color == 'blue' or color == 'cyan' or color == 'white' or color == 'green':
                color = 'normal'
    return color

if __name__ == '__main__':
    filename = "C:/Users/admin/Desktop/water_samples/live01.jpg"
    frame = cv2.imread(filename)
    # frame = frame[180:280, 180:380]  # [y:y+h, x:x+w] 注意x,y順序
    color = get_color(frame)

    # 繪製文字
    cv2.putText(img=frame,text=color,org=(20,50),fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                fontScale=1.0,color=(0,255,0),thickness=2)

    # cv2.namedWindow('frame',cv2.WINDOW_NORMAL)  # 設定顯示視窗可調節
    cv2.imshow('frame',frame)
    cv2.waitKey(0)

video_color_realize.py

import cv2
import xf_color


# 對視訊或攝像頭獲取的影像目標區域顏色進行識別

cap = cv2.VideoCapture("C:/Users/admin/Desktop/water_samples/01.mp4")
# cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1100)  # 這裡視窗大小調節只對攝像頭有效
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 750)

while cap.isOpened():
    ret, frame0 = cap.read()
    # 對影象幀進行翻轉(因為opencv影象和我們正常是反著的) 視訊是正常的,攝像頭是反轉的
    # frame0 = cv2.flip(src=frame0, flipCode=2)

    # frame = frame[180:280, 180:380]  # [y:y+h, x:x+w]
    # frame = frame0[200:400, 100:300]  # 設定檢測顏色的區域,四個頂點座標
    frame = frame0

    # frame=cv2.resize(src=frame,dsize=(750,600))
    hsv_frame = cv2.cvtColor(src=frame, code=cv2.COLOR_BGR2HSV)
    # 獲取讀取的幀的高寬
    height, width, channel = frame.shape
    color = xf_color.get_color(hsv_frame)
    # 繪製文字
    cv2.putText(img=frame0, text=color, org=(20, 50), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                fontScale=1.0, color=(0, 255, 0), thickness=2)
    cv2.imshow('frame', frame0)
    key = cv2.waitKey(1)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()


if __name__ == '__main__':
    print('Pycharm')

效果如下:

範例圖片1

範例圖片2

範例圖片3