Smon
Smon

Reputation: 1

count red color object from video opencv python

I'm trying to count how many red color bar from this video

tes1.mp4

and this is my function to count the object by count the center of the object

def count(frame):
frame = imutils.resize(frame,640,480)
hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv, lower, upper)
contours,_ = cv2.findContours(mask.copy(), cv2.RETR_CCOMP,cv2.CHAIN_APPROX_TC89_L1)
center=[]

for i in range(len(contours)):
    c = max(contours, key=cv2.contourArea)
    ((x, y), radius) = cv2.minEnclosingCircle(c)
    M = cv2.moments(c)
    if M["m00"]==0:
        M["m00"]=0.6
    cx=int (M["m10"]/M["m00"])
    cy=int(M["m01"] / M["m00"])
    print "center",len(center)

    center.append((cx,cy))
    cv2.circle(frame, center[-1],3,(0,0,0),-1)

but the problem is len(center) appear more than 300. can anyone help to count how many the red bar. any solution will be helpful.

Upvotes: 0

Views: 1827

Answers (2)

Headcrab
Headcrab

Reputation: 7103

Here's how I made it: first, subtract blue and green channels from the red channel to find the "red" pixels. The result looks like this:

enter image description here

Threshold works really well on this, obviously:

enter image description here

From here we can find contours:

enter image description here

Count them, and that's the number of stripes. But there's also connectedComponents function, it can count those without finding contours.

import cv2
import numpy as np

#load a frame as int16 array to avoid overflow etc. when subtracting
img = cv2.imread("test_images/redbars.png").astype(np.int16)

#separating into blue, green and red channels
img_b = img[:, :, 0]
img_g = img[:, :, 1]
img_r = img[:, :, 2]

#for a red stripe, the red component should be much bigger than the rest
res_br = img_r - img_b
res_gr = img_r - img_g
res = np.maximum(res_br, res_gr)
res[res < 0] = 0
res = res.astype(np.uint8)  #convert back to uint8 for findContours etc.

ret, thresh = cv2.threshold(res, 50, 1, cv2.THRESH_BINARY)

#find contours and count them
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#gives the correct output of 5
print(len(contours))

#alternatively, count connected components with this:
ncomp, nimg = cv2.connectedComponents(thresh)
print(ncomp - 1)  #it counts the background as one of the components, so subtract 1

Upvotes: 1

Elouarn Laine
Elouarn Laine

Reputation: 1695

Here is a pipeline you can use to count the number of red strips on a frame:

int main(int argc, char** argv)
{
    Mat input = imread("red_lines.png");
    Mat hsv;
    cvtColor(input, hsv, CV_BGR2HSV);

    Mat mask;
    inRange(hsv, Scalar(0, 0,0), Scalar(15, 255,255), mask);

    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(7, 7));
    erode(mask, mask, kernel);
    dilate(mask, mask, kernel);

    vector<vector<Point>> contours;
    findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    cout << "objects found: " << contours.size() << endl;

    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(input, contours, i, Scalar(0, 255, 0), 2);
    }

    imshow("mask", mask);
    imshow("contours", input);
    waitKey(0);

    return 0;
}

The important part in my code, is the morphological operations (erosion then dilation) I apply on the mask (resulting from inRange). This allows to remove the "mask's noise" and thus to catch only the big red strips.

Red strips with a green outline

To further improve the robustness, I recommend you to check the area of each contour. If it is above a certain threshold, just discard it.

P.S. This is C++ code, but I'm sure you'll figure out how to translate it into Python code... :)

Upvotes: 0

Related Questions