how to detect multiple objects using ORB features matching?

108 views Asked by At

I'm a newbie here in Image Recognition. Currently, I'm making traffic sign detection from a video using OpenCV library in python. It work well if I use template matching function that provided by openCV. But when I tried to use ORB, it works well on single image of the object i want to recognize and completely useless if I feed a video to the program. So, I take an approach which split the video feed as 4 different section. Here is the code I created:

import numpy as np
import cv2 
import os

orb = cv2.ORB_create(10000)
# orb = cv2.ORB_create(10000, nlevels=8, edgeThreshold=5)
PATH_TEMPLATE = "img/template"
images = []
classNames = []
classFound = [0,0]
path_list = os.listdir(PATH_TEMPLATE)
for className in path_list:
    currentImage = cv2.imread(f'{PATH_TEMPLATE}/{className}',0)
    # currentImage = cv2.resize(currentImage, (0,0), fx=0.7, fy=0.7)
    images.append(currentImage)
    classNames.append(className.split(".")[0])

print(classNames)

# Create Descriptor for each image class 
def createDesc(images):
    descList = []
    for img in images:
        keypoint, descriptor = orb.detectAndCompute(img,None)
        descList.append(descriptor)
    return descList

descList = createDesc(images)
print(len(descList))
# print(descList)

# Create matcher 
def checkMatch(img, descList):
    img_keypoint, img_descriptor = orb.detectAndCompute(img,None)
    # print(img_descriptor)
    bf = cv2.BFMatcher()
    matchListLen = []
    matchList = []
    # Loop trough defined Class Descriptor 
    for desc in descList:
        if (img_descriptor is not None):
            matches = bf.knnMatch(desc, img_descriptor, k=2)
            goodMatches = []
            
            # Loop Through matches 
            for m,n in matches:
                
                # Check if the matches near to each other 
                if m.distance < 0.75 * n.distance:
                    goodMatches.append([m])
            # Loop Through matches 
            # for x in range(0, len(matches) - 1):
                
            #     # Check if the matches near to each other 
            #     if matches[x][0].distance < 0.5 * matches[x + 1][0].distance:
            #         goodMatches.append([matches[x]])

            matchListLen.append(len(goodMatches))
            matchList.append(goodMatches)
        
    return matchList, matchListLen

#Find detected class
def getClass(matches, threshold = 15):
    # print(matches)
    finalClass = -1
    if (len(matches) != 0):
        if max(matches) > threshold:
            finalClass = matches.index(max(matches))
            
    return finalClass


def singleObjDetect(filename):
    #Test image
    imgTest = cv2.imread(f"img/{filename}")
    imgTestG = imgTest.copy()
    # imgTestG = cv2.cvtColor(imgTestG, cv2.COLOR_BGR2GRAY)

    matchRaw, matchLen = checkMatch(imgTestG, descList)
    classID = getClass(matchLen)
    if (classID != -1):
        print(f'Detected: {classNames[classID]}')
    else:
        print("Undetected")


def sceneObjDetect(filename):
    imgTest = cv2.imread(f"img/{filename}")
    imgTestG = imgTest.copy()
    
    M = imgTestG.shape[0] // 3
    N = imgTestG.shape[1] // 3

    imgTestG = imgTestG[0:M*3, 0:N*3]
    

    imgTiles = [imgTestG[x:x+M,y:y+N] for x in range(0, imgTestG.shape[0], M) for y in range(0, imgTestG.shape[1], N) ]

    for x in range(0, len(imgTiles)):
        print(f'Tile: {x}')
        
        matchRaw, matchLen = checkMatch(imgTiles[x], descList)
        classID = getClass(matchLen)
        if (classID != -1):
            print(f'Detected: {classNames[classID]}')
        else:
            print("Undetected")
        
        cv2.imshow(f'Tile {x}', imgTiles[x])
    cv2.waitKey(0)
    
    
def sceneRealObjDetect(filename, threshold = 15):
    vid = cv2.VideoCapture(f"vid/{filename}")
    while True:
        ret, frame = vid.read()
        if not ret:
            break
        imgTestG = frame.copy()
        # imgTestG = cv2.cvtColor(imgTestG, cv2.COLOR_BGR2GRAY)
        
        M = imgTestG.shape[0] // 2
        N = imgTestG.shape[1] // 2

        imgTestG = imgTestG[0:M*2, 0:N*2]
        
        # print(f"H:{imgTestG.shape[0]} W:{imgTestG.shape[1]}")
        
        imgTiles = [imgTestG[x:x+M,y:y+N] for x in range(0, imgTestG.shape[0], M) for y in range(0, imgTestG.shape[1], N) ]

        for x in range(0, len(imgTiles)):
            # print(f'Tile: {x}')
            # print(f'Tile Size {imgTiles[x].shape[1]} x {imgTiles[x].shape[0]}')
            
            matchRaw, matchLen = checkMatch(imgTiles[x], descList)
            classID = getClass(matchLen,threshold)
            if (classID != -1):
                # print(f'Detected: {classNames[classID]}')
                classFound[classID] += 1
                cv2.putText(imgTiles[x], f'Detected: {classNames[classID]} deb: {matchLen}',(imgTiles[x].shape[1] // 2, imgTiles[x].shape[0] // 2),cv2.FONT_HERSHEY_PLAIN, 1, (0,255,0), 1)
            else:
                # print("Undetected")
                cv2.putText(imgTiles[x], f"Undetected  deb: {matchLen}",(imgTiles[x].shape[1] // 2, imgTiles[x].shape[0] // 2),cv2.FONT_HERSHEY_PLAIN, 1, (0,0,255), 1)
                
            cv2.imshow(f'Tile: {x}', imgTiles[x])
            # cv2.imshow("Video", vid)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        
    vid.release()


# testing 
sceneRealObjDetect("test-drive-720.mp4", 18)
print(classFound)
# singleObjDetect("green-life.png")


I wonder how to detect multiple traffic sign recognition without spliting the video into 4 section. I hvae tried some different approach but it resulting error. Since, I'm a newbie i want to know how to achieve the multiple traffic sign detection using ORB.

0

There are 0 answers