Reputation: 1
I'm trying to count how many red color bar from this video
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
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:
Threshold works really well on this, obviously:
From here we can find contours:
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
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.
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