6. Web-camera and traffic-light controlΒΆ

The traffic light control is implemented through OpenCV videocapture system. The class TimeAdviser implements the traffic light control feature of the system.

class TimeAdvicer:
"""
Main class for the car detection.
Captures the road image and finds cars on it.
"""
def __init__(self, camN=0, file1="test1.jpg", file2="test2.jpg"):
    """

    :param camN: Number of device /dev/video*
    :param file1: Outfile for the first part of the road
    :param file2: Outfile for the second part of the road
    """
    self.cam=cv2.VideoCapture(camN)
    self.file1=file1
    self.file2=file2
    self.broken=False

The system requires the empty road to be shown at the beginning. Function TEST is called to detect the road and to print out parts of the road. This allows to find the zones of interest, which are parts of the crossroad.

def test(self):
"""
Detects the road and print it as two images.
:return: True if the road has been detected. False otherwise.
"""
    #Road detection indicator
    flag=False
    #Capture the road image from the webcam
    ret, image = self.cam.read()
    #Get the objects' borders
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(blurred, 50, 200, 255)

    # Find contours in the edge map, then sort them by their
    # Size in descending order
    cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

    #Set of contours' points
    displayCnt = None

    # Loop over the contours
    for c in cnts:
        # Approximate the contour
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)

        # If the contour has four vertices, then we have found
        # the thermostat display
        if (len(approx) == 12) and (cv2.contourArea(c)>=1000):
            displayCnt = approx

            #Debug mode
            flag=True
            break
    # X and Y of contour points
    roadx = []
    roady = []

    for i in displayCnt:
        roadx.append(i[0][0])
        roady.append(i[0][1])

    # Get the set of the contours' points
    pts = []
    for i in range(0, len(roadx)):
        pts.append([roadx[i], roady[i]])

    # Get the array with border numbers
    convexNums = grahamscan(pts)


    xFirst = convexNums[0]
    # Getting first half of the road

    firstHalfRoad = [point for point in convexNums if (isNear((pts[point])[0], (pts[xFirst])[0]) \
                                                       or isNear((pts[point])[1],
                                                                 (pts[xFirst])[1])) and point != xFirst]

    firstRoad = [point for point in convexNums if (isNear((pts[point])[0], (pts[firstHalfRoad[0]])[0]) \
                                                   or isNear((pts[point])[1],
                                                             (pts[firstHalfRoad[0]])[1])) and point !=
                 firstHalfRoad[0]] + firstHalfRoad
    # Other half of the road
    secondRoad = [i for i in set(convexNums) - set(firstRoad)]

    # Get two rectangles for the road recognition
    localApproxFirstRoad = [[[]]]
    localApproxSecondRoad = [[[]]]
    for y in firstRoad:
        localApproxFirstRoad.append([[pts[y]]])
    localApproxFirstRoad.pop(0)
    for y in secondRoad:
        localApproxSecondRoad.append([[pts[y]]])
    localApproxSecondRoad.pop(0)

    self.coordsOfFirstRoad = np.array(localApproxFirstRoad)
    self.coordsOfSecondRoad = np.array(localApproxSecondRoad)

    # Print out the road parts to images
    r1 = four_point_transform(gray, self.coordsOfFirstRoad.reshape(4, 2))
    cv2.imwrite(self.file1, r1)
    r2 = four_point_transform(gray, self.coordsOfSecondRoad.reshape(4, 2))
    cv2.imwrite(self.file2, r2)
    return flag

The function returns true and gives two files with given names, which are parts of the road, if the road has been detected. The example of the output images:

_images/image12.jpg _images/image20.jpg

After that, connected-components analysis helps to find cars on the road. The function getCarN is implemented to count the number of cars which are on the road.

def getCarN(self):
"""
Detects objects on the road
:return: The number of cars on both first and second roads as x,y
"""
try:
    if self.broken==True:
        return 1, 1
    # Get the road images
    ret, image = self.cam.read()
    # Get the objects' borders
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    r1 = four_point_transform(gray, self.coordsOfFirstRoad.reshape(4, 2))
    cv2.imwrite(self.file1, r1)
    r2 = four_point_transform(gray, self.coordsOfSecondRoad.reshape(4, 2))
    cv2.imwrite(self.file2, r2)

    # Calculate the threshold
    mean = 0
    for i in r1:
        for j in range(0, len(i)):
            mean += i[j]
    mean = mean / (len(r1) - 1) / (len(r1[0]) - 1)

    # Get the car imaga on the road
    blurred = cv2.GaussianBlur(r1, (11, 11), 0)
    thresh = cv2.threshold(blurred, mean * 0.8, 255, cv2.THRESH_BINARY_INV)[1]
    thresh = cv2.erode(thresh, None, iterations=2)
    thresh = cv2.dilate(thresh, None, iterations=4)
    labels1 = measure.label(thresh, neighbors=8, background=0, return_num=True)
    cv2.imwrite(self.file1, thresh)

    #Same for the second road
    mean = 0
    for i in r2:
        for j in range(0, len(i)):
            mean += i[j]
    mean = mean / (len(r2) - 1) / (len(r2[0]) - 1)
    blurred = cv2.GaussianBlur(r2, (11, 11), 0)
    thresh = cv2.threshold(blurred, mean * 0.8, 255, cv2.THRESH_BINARY_INV)[1]
    thresh = cv2.erode(thresh, None, iterations=2)
    thresh = cv2.dilate(thresh, None, iterations=4)
    labels2 = measure.label(thresh, neighbors=8, background=0, return_num=True)
    cv2.imwrite(self.file2, thresh)
    # Return the number of connected components
    return labels1[1], labels2[1]

The simple intermediate result of the analysis is the following.

_images/image03.jpg

The output is how many cars are currently on the road. Depending on the traffic, server will set the necessary timer value.