I want to track a moving fish from camera witch has located on top of a fish tank. Till now I was able to track the multiple moving objects using moving average and background subtraction methods. And I put text on each contour. But the problem is I couldn't keep the same label for same moving fish. Fish can detect from every frame but tracked object number is changing. I have attached my current Python code. What am I doing wrong here? Can someone tell me a another possible way to do this?
import cv2
import numpy as np
device = cv2.VideoCapture(0)
flag, frame = device.read()
movingaverage = np.float32(frame)
background = cv2.createBackgroundSubtractorMOG2()
font=cv2.FONT_HERSHEY_SIMPLEX
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))
while True:
flag, frame = device.read()
alpha = float(1.0/2.0)
cv2.accumulateWeighted(frame,movingaverage,alpha)
gaussion = background.apply(frame)
res = cv2.convertScaleAbs(movingaverage)
difference_img = cv2.absdiff(res, frame)
grey_difference_img = cv2.cvtColor(difference_img, cv2.COLOR_BGR2GRAY)
ret,th1 = cv2.threshold(grey_difference_img, 10, 255, cv2.THRESH_BINARY)
combine = cv2.bitwise_and(gaussion, gaussion, mask = grey_difference_img)
_, conts, h1 =cv2.findContours(combine.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
if len(conts) == 0:
cv2.putText(frame,"No moving objects found!",(50,200), font, 1,(255,255,255),2,cv2.LINE_AA)
else:
number = 0
for i in range(len(conts)):
x,y,w,h = cv2.boundingRect(conts[i])
if (w > 50) and (h > 50):
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255), 2)
cv2.putText(frame,str(number +1)+ "object",(x,y+h), font, 1,(255,255,255),2,cv2.LINE_AA)
number = number + 1
cv2.imshow("Gaussian",gaussion)
cv2.imshow("Track",frame)
if cv2.waitKey(1) == 27:
break
device.release()
cv2.destroyAllWindows()
I have an idea but I'm not sure about that. Now I have modified the code to detect center of each and every contour. So, can I store the information about the coordinates to an array, then check the new frame contours center point such that close to array values. Then try to guess the contour which stored in array in previous frame. I don't know the possibility of this since I'm new to Python and OpenCV.
if (w > 50) and (h > 50):
cnt = conts[i]
M = cv2.moments(cnt)
if M['m00'] != 0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
#draw a circle at center of contours.
cv2.circle(frame,(cx,cy), 2, (0,0,255), -1)
print( "(",cx,",",cy,")" )
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255), 2)
cv2.putText(frame,str(number +1)+ "object",(x,y+h), font, 1,(255,255,255),2,cv2.LINE_AA)
I have edited my code. Now it works fine if the moving objects are in the same horizontal plane. What I did was, create list called matched_contours and paths. Then append calculated center points into paths which in element of matched_contours. And used min_dist to check whether contours has presented in previous frame or not. If it has presented I have updated new center points in matched_contour. If not, I took it as a new matched_contour.
THIS IS THE UPDATED PART
im2, contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
for (_, contour) in enumerate(contours):
(x, y, w, h) = cv2.boundingRect(contour)
if (w >= 50) or (h >= 50): # Find targeting size moving objects
x1 = int(w / 2)
y1 = int(h / 2)
cx = x + x1
cy = y + y1
if len(matched_contours) == 0: #No previous moving objects
paths = []
paths.append((cx,cy))
object_num = object_num + 1
matched_contours.append(((x, y, w, h), (cx,cy), object_num, paths))
cv2.circle(frame,(cx,cy), 2, (0,0,255), -1)
#cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255), 2)
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(frame,[box],0,(0,255,0),2)
cv2.putText(frame,"object " + str(object_num),(x,y+h), font, 0.5,(255,255,255),1,cv2.LINE_AA)
else:
found = False
for i in range(len(matched_contours)):
ponits, center, num, path = matched_contours[i]
old_cx, old_cy = center
#Calculate euclidian distances between new center and old centers to check this contour is existing or not
euc_dist = math.sqrt(float((cx - old_cx)**2) + float((cy - old_cy)**2))
if euc_dist <= min_dist:
if len(path) == max_path_length:
for t in range(len(path)):
if t == max_path_length - 1:
path[t] = (cx,cy)
else:
path[t] = path[t+1]
else:
path.append((cx,cy))
matched_contours[i] = ((x, y, w, h), (cx,cy), num, path)
cv2.circle(frame,(cx,cy), 2, (0,0,255), -1)
#cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255), 2)
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(frame,[box],0,(0,255,0),2)
cv2.putText(frame,"object " + str(num),(x,y+h), font, 0.5,(255,255,255),1,cv2.LINE_AA)
#Draw path of the moving object
for point in range(len(path)-1):
cv2.line(frame, path[point], path[point+1], (255,0,0), 1)
cv2.circle(frame,path[point+1], 3, (0,0,255), -1)
if not found: #New moving object has found
object_num = object_num + 1
paths = []
paths.append((cx,cy))
matched_contours.append(((x, y, w, h), (cx,cy), object_num, paths))
cv2.circle(frame,(cx,cy), 2, (0,0,255), -1)
#cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255), 2)
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(frame,[box],0,(0,255,0),2)
cv2.putText(frame,"object " + str(object_num),(x,y+h), font, 0.5,(255,255,255),1,cv2.LINE_AA)
Related
I'm putting together an image processing tool to follow the deformation of a part using images. The part has rectangular markers that get detected with image segmentation and cv2.findContours function. Contour centers are then used to calculate distances and to bend radiuses. Everything seems to work fine, but I found out that the contours aren't sorted how I would like to sort them when reviewing results.
The part is repeatedly bent, and the contours are positioned in a circle.
I found this article that describes the sorting horizontally and vertically:
https://www.pyimagesearch.com/2015/04/20/sorting-contours-using-python-and-opencv/
Does anyone have any idea how to sort the contours in a clockwise direction?
The code is below.
import os
import exifread
import cv2
import numpy as np
import scipy
from matplotlib import pyplot as plt
import imutils
import pandas as pd
#---------- INPUT ----------
# Define the image filename
img_filename = 'frame397.jpg'
img_path = img_filename
# Define values for cropping
x = 0
y = 200
w = 1200
h = 800
# Define color values for segmentation
# the values can be probed with GIMP
h1 = 0
s1 = 70
v1 = 120
h2 = 255
s2 = 255
v2 = 255
red_lower = np.array([h1,s1,v1])
red_upper = np.array([h2,s2,v2])
# Define desired area size
# desired area size is pixel count - use GIMP for probe
s1 = 500
s2 = 10000
#---------- PROCESS IMAGES ----------
# Create an empty dataframe for storing results
# in shape of (image_name,time,angle,angle_smooth,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11)
# Define the results dataframe shape and column names
results_df = pd.DataFrame(columns=['image_name','alpha','r1','r2','r3','r4','r5','r6','r7','r8','r9','r10','r11',
'center_dist1', 'center_dist2','center_dist3','center_dist4',
'center_dist5','center_dist6','center_dist7','center_dist8',
'center_dist9','center_dist10','center_dist11'])
# Open image, make it black and white and find contours
img = cv2.imread(img_path)
crop = img[y:y+h, x:x+w]
blur = cv2.blur(crop,(2,2))
hsv = cv2.cvtColor(blur,cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, red_lower, red_upper)
mask_copy = mask.copy()
cnts = cv2.findContours(mask_copy,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
#print cnts
x = []
y = []
# Loop through contours, calculate the centers and prepare the
#contours and contour centers display
#define the font for the text on the image
font = cv2.FONT_HERSHEY_SIMPLEX
for cnt in cnts:
area = cv2.contourArea(cnt)
moment = cv2.moments(cnt)
if s1<area<s2:
print area
c_x = int(moment["m10"]/moment["m00"])
c_y = int(moment["m01"]/moment["m00"])
#draw contours
cv2.drawContours(crop, cnt, -1, (0,255,0),3)
#draw a circle in the center of every contour, -1 is for thickness, this means
#that the cirlce will get filled in
cv2.circle(crop, (c_x,c_y), 10, (0,255,0),-1)
#display center coordinates on the image
string = str(c_x) + ',' + str(c_y)
cv2.putText(crop,string,(c_x,c_y),font,0.5,(255,255,255),2)
x.append(float(c_x))
y.append(float(c_y))
print (c_x, c_y)
print x
print y
# Display image
cv2.namedWindow('Contours', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Contours', 1200,900)
cv2.imshow('Contours', crop)
# Wait for windows closing
cv2.waitKey() & 0xFF
cv2.destroyAllWindows
Image is here:
I used openCV's minEnclosingCircle to "fit" a circle to the points (it's not actually a fit, but it's good enough for finding a point inside the curvature of the markers). Marking each contour with the angle from its centroid to the circle's center gave me a set of angles that I could sort with.
import cv2
import numpy as np
import math
# 2d distance
def dist2D(one, two):
dx = one[0] - two[0];
dy = one[1] - two[1];
return math.sqrt(dx*dx + dy*dy);
# angle between three points (the last point is the middle)
def angle3P(p1, p2, p3):
# get distances
a = dist2D(p3, p1);
b = dist2D(p3, p2);
c = dist2D(p1, p2);
# calculate angle // assume a and b are nonzero
# (law of cosines)
numer = c**2 - a**2 - b**2;
denom = -2 * a * b;
if denom == 0:
denom = 0.000001;
rads = math.acos(numer / denom);
degs = math.degrees(rads);
# check if past 180 degrees
if p1[1] > p3[1]:
degs = 360 - degs;
return degs;
# load image
img = cv2.imread("slinky.jpg");
# rescale
scale = 0.5;
h, w = img.shape[:2];
h = int(h * scale);
w = int(w * scale);
img = cv2.resize(img, (w,h));
# change color space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB);
l,a,b = cv2.split(lab);
# threshold
thresh = cv2.inRange(a, 140, 255);
# get rid of little dots
kernel = np.ones((3,3),np.uint8)
thresh = cv2.erode(thresh,kernel,iterations = 1);
thresh = cv2.dilate(thresh,kernel, iterations = 1);
# contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# get centroids
centroids = [];
centers = [];
for con in contours:
m = cv2.moments(con);
cx = int(m['m10'] / m['m00']);
cy = int(m['m01'] / m['m00']);
centers.append([cx, cy]);
centroids.append([[cx, cy], con]);
img = cv2.circle(img, (cx, cy), 10, (0,0,255), -1);
# find circle around points
# NOTE: this doesn't "fit" a circle to the points
# I'm just using this to find a "good enough" center
# that's in the direction of the curve
numped = np.array(centers);
(x, y), radius = cv2.minEnclosingCircle(numped);
img = cv2.circle(img, (int(x), int(y)), int(radius), (255,0,0), 2);
middle = [x,y];
offshoot = [x + 100, y];
# get angles
angles = [];
for cen in centroids:
center, contour = cen;
angle = angle3P(center, offshoot, middle);
angles.append([angle, center, contour]);
# sort by angle
final = sorted(angles, key = lambda a: a[0], reverse = True);
# pull out just the contours
contours = [clump[2] for clump in final];
# draw contours in order
marked = img.copy();
counter = 0;
for con in contours:
cv2.drawContours(marked, [con], -1, (0, 255, 0), 2);
cv2.imshow("marked", marked);
cv2.imwrite("marking_seq/" + str(counter) + ".png", marked);
counter += 1;
cv2.waitKey(0);
# show
cv2.imshow("orig", img);
cv2.imshow("a", a);
cv2.imshow("thresh", thresh);
cv2.waitKey(0);
In my image processing project, I have already obtained a masked image (black-and-white image) and its contours using the cv.findContours function. My goal now is to create an algorithm that can draw a middle line for this contour. The masked image and its contour are shown in the following images.
Masked image:
Contour:
In my imagination, for that contour, I would like to create a middle line which is near horizontal. I have manually marked my ideal middle line in red. Please check the following image for the red middle line that I have mentioned.
Contour with the middle line:
It is noticeable that my ultimate goal is to find the tip point that I have marked in yellow. If you have other ideas that can directly find the yellow tip point, please also let me know. For finding the yellow tip point, I have tried two approaches cv.convexHull and cv.minAreaRect, but the issue is the robustness. I made these two approaches worked for some images but for some other images in my dataset, they are not working very well. Therefore, I think to find the middle line might be a good approach that I can try.
I believe you're trying to determine the contour's center of gravity and orientation. We can easily do this using Central Moments. More info on that here.
The code below generates this plot. Is this the result you wanted?
# Determine contour
img = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)
img_bin = (img>128).astype(np.uint8)
contours, _ = cv2.findContours(img_bin, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE)
# Determine center of gravity and orientation using Moments
M = cv2.moments(contours[0])
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
theta = 0.5*np.arctan2(2*M["mu11"],M["mu20"]-M["mu02"])
endx = 600 * np.cos(theta) + center[0] # linelength 600
endy = 600 * np.sin(theta) + center[1]
# Display results
plt.imshow(img_bin, cmap='gray')
plt.scatter(center[0], center[1], marker="X")
plt.plot([center[0], endx], [center[1], endy])
plt.show()
My goal right now is to create an algorithm that can draw a middle line for this contour.
If you detect the upper and lower bounds of your horizontal-lines, then you can calculate the middle-line coordinates.
For instance:
Middle-line will be:
If you change the size to the width of the image:
Code:
import cv2
img = cv2.imread("contour.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(h, w) = img.shape[:2]
x1_upper = h
x1_lower = 0
x2_upper = h
x2_lower = 0
y1_upper = h
y1_lower = 0
y2_upper = h
y2_lower = 0
lines = cv2.ximgproc.createFastLineDetector().detect(gray)
for cur in lines:
x1 = cur[0][0]
y1 = cur[0][1]
x2 = cur[0][2]
y2 = cur[0][3]
# upper-bound coords
if y1 < y1_upper and y2 < y2_upper:
y1_upper = y1
y2_upper = y2
x1_upper = x1
x2_upper = x2
elif y1 > y1_lower and y2 > y2_lower:
y1_lower = y1
y2_lower = y2
x1_lower = x1
x2_lower = x2
print("\n\n-lower-bound-\n")
print("({}, {}) - ({}, {})".format(x1_lower, y1_lower, x2_lower, y2_lower))
print("\n\n-upper-bound-\n")
print("({}, {}) - ({}, {})".format(x1_upper, y1_upper, x2_upper, y2_upper))
cv2.line(img, (x1_lower, y1_lower), (x2_lower, y2_lower), (0, 255, 0), 5)
cv2.line(img, (x1_upper, y1_upper), (x2_upper, y2_upper), (0, 0, 255), 5)
x1_avg = int((x1_lower + x1_upper) / 2)
y1_avg = int((y1_lower + y1_upper) / 2)
x2_avg = int((x2_lower + x2_upper) / 2)
y2_avg = int((y2_lower + y2_upper) / 2)
cv2.line(img, (0, y1_avg), (w, y2_avg), (255, 0, 0), 5)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I beleive skeleton is what you are looking for.
import cv2
import timeit
img = cv2.imread('Ggh8d - Copy.jpg',0)
s = timeit.default_timer()
thinned = cv2.ximgproc.thinning(img, thinningType = cv2.ximgproc.THINNING_ZHANGSUEN)
e = timeit.default_timer()
print(e-s)
cv2.imwrite("thinned1.png", thinned)
if smooth the edge a little bit
Actually the line will not torch the yellow point, since the algorithm have to check distance from edges, yellow point is located on the edge.
Here is another way to do that by computing the centerline of the rotated bounding box about your object in Python/OpenCV.
Input:
import cv2
import numpy as np
# load image
img = cv2.imread("blob_mask.jpg")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold the grayscale image
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
# get coordinates of all non-zero pixels
# NOTE: must transpose since numpy coords are y,x and opencv uses x,y
coords = np.column_stack(np.where(thresh.transpose() > 0))
# get rotated rectangle from
rotrect = cv2.minAreaRect(coords)
box = cv2.boxPoints(rotrect)
box = np.int0(box)
print (box)
# get center line from box
# note points are clockwise from bottom right
x1 = (box[0][0] + box[3][0]) // 2
y1 = (box[0][1] + box[3][1]) // 2
x2 = (box[1][0] + box[2][0]) // 2
y2 = (box[1][1] + box[2][1]) // 2
# draw rotated rectangle on copy of img as result
result = img.copy()
cv2.drawContours(result, [box], 0, (0,0,255), 2)
cv2.line(result, (x1,y1), (x2,y2), (255,0,0), 2)
# write result to disk
cv2.imwrite("blob_mask_rotrect.png", result)
# display results
cv2.imshow("THRESH", thresh)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
I'm a new coder and I work on graduation project with OpenCV library [Python code].
I need to write code to detect balloon in the constant background and monitor it.
I decided to work with Substruct function + HoughCircles, the problem is that every code is working good [except the Circle detection which working not the best], When I combine the two codes It works super slowly and stuck ALOT, can someone suggest me please how to insert it right so it wont stuck and somehow improve the HoughCircles?
import numpy as np
#import RPi.GPIO as GPIO
import time
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
#changes = sum(sum(fgmask>200))
changes = (fgmask>200).sum() #
is_moving = (changes > 10000)
print(changes, is_moving)
items = []
contours, hier = cv2.findContours(fgmask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if 200 < area:
(x,y,w,h) = cv2.boundingRect(cnt)
cv2.rectangle(fgmask, (x,y),(x+w,y+h),255, 2)
cv2.rectangle(frame, (x,y),(x+w,y+h),(0,255,0), 2)
items.append( (area, x, y, w, h) )
if items:
main_item = max(items)
area, x, y, w, h = main_item
if w > h:
r = w//2
else:
r = h//2
cv2.circle(frame, (x+w//2, y+h//2), r, (0,0,255), 2)
print(x + w // 2, y + h // 2)
circles = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,50,
param1=50,param2=30,minRadius=0,maxRadius=0)
#circles = np.uint16(np.around(circles))
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle in the image
# corresponding to the center of the circle
cv2.circle(gray, (x, y), r, (0, 255, 0), 4)
#cv2.rectangle(gray, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
# time.sleep(0.5)
print("Column Number: ")
print(x)
print("Row Number: ")
print(y)
print("Radius is: ")
print(r)
cv2.imshow('fgmask', fgmask)
cv2.imshow('frame', frame)
cv2.imshow('gray',gray)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
Thank you very much!
I am working on counting software. I have successfully detected the products and want to count them. For counting, I have defined two-line and if centroid is between two lines the product is counted. Two problems I am facing. First, since my product is coming very fast some product is not falling between lines so, I increased the linespace. Second, after increasing the linespace if the products are falling two times then it is counted twice. I tried to put centroid in a list and if products are counted once, I deleted elements of the list. Count is twice or wrong. Please help.
Here is the video link
https://drive.google.com/file/d/1Gqp937OlDpF4_Nx2kSOzHw3A85Xch-HX/view?usp=sharing
import cv2
import math
import numpy as np
width = 0
height = 0
EntranceCounter = 0
ExitCounter = 0
OffsetRefLines = 120
QttyOfContours = 0
area = 0
detect = []
area_min = 100
area_max = 4000
BinarizationThreshold = 70
#Check if an object in entering in monitored zone
##def CheckEntranceLineCrossing(CoordYCentroid, CoorYEntranceLine,CoorYExitLine,area):
## AbsDistance = abs(CoordYCentroid - CoorYEntranceLine)
## if ((y>CoorYEntranceLine) and (y < CoorYExitLine) ):#and area>=5000):
## return 1
## #else:
## #return 0
cap = cv2.VideoCapture('testvideo.avi')
while(cap.isOpened()):
ret, frame = cap.read()
height = np.size(frame,0)
width = np.size(frame,1)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
_, threshold = cv2.threshold(frame, 100, 255, cv2.THRESH_BINARY)
low = np.array([0,0,0])
high = np.array([60, 60, 60])
image_mask = cv2.inRange(threshold,low, high)
contours,_= cv2.findContours(image_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(frame, contours, -1, (0,255,0), 3)
CoorYEntranceLine = int(150-OffsetRefLines)
CoorYExitLine = int(150+OffsetRefLines)
cv2.line(threshold, (0,CoorYEntranceLine), (width,CoorYEntranceLine), (0, 255, 0), 2)
cv2.line(threshold , (0,CoorYExitLine), (width,CoorYExitLine), (0, 0, 255), 2)
for (i,c) in enumerate(contours):
new = True
QttyOfContours = QttyOfContours+1
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(threshold, (x, y), (x + w, y + h), (0, 0, 255), 2)
area = cv2.contourArea(c)
if area< area_min:
continue
#find object's centroid
CoordXCentroid = int((x+x+w)/2)
CoordYCentroid = int((y+y+h)/2)
ObjectCentroid = (CoordXCentroid,CoordYCentroid)
#center = pega_centro(x, y, w, h)
center = (CoordXCentroid,CoordYCentroid)
detect.append(center)
for (x,y) in detect:
if ((y < CoorYExitLine) and (y>CoorYEntranceLine) and (area>area_min) and (area<area_max)):
if new ==True:
EntranceCounter += 1
detect.clear()
break
cv2.putText(frame, str(EntranceCounter), ((CoordXCentroid),(CoordYCentroid-50)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
cv2.putText(threshold, "Entrances: {}".format(str(EntranceCounter)), (10, 50),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (250, 0, 1), 2)
cv2.imshow('fram1',threshold)
cv2.imshow('frame',frame)
if cv2.waitKey(1)==27:
break
cap.release()
cv2.destroyAllWindows()
Just check intersection of counting line and line between current and previous object position points. And, as extra guaranty, use "counted" flag for tracked objects.
Im working in python and opencv library.
I can threshold a camera capture, find contours (more than one) and draw.
But I have a problem. I try to identify those contours with an unique id or tag. (for example: Id: 1 , Id:2) to track them.
I need this contours use a persistent id.
The goal is draw a line and count more than one contour and sometimes more than one near contours converts in a big one.
Note: Im working with a depth camera and my image its an array of depth.
add a piece of code.
Thanks in advance.
countours = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
# only proceed if at least one contour was found
if len(countours) > 0:
# find the largest contour in the mask, then use
# it to compute the minimum enclosing circle and
# centroid
for (i,c) in enumerate(countours):
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
if M["m00"] > 0:
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
centerString = str(center)
x = (int(M["m10"] / M["m00"]))
y = (int(M["m01"] / M["m00"]))
else:
center = int(x), int(y)
if radius > 10:
# draw the circle and centroid on the frame,
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
# then update the ponter trail
if self.previous_position:
cv2.line(self.trail, self.previous_position, center,
(255, 255, 255), 2)
cv2.add(self.trail, frame, frame)
print center
self.previous_position = center
if len(countours) < 1:
center = 0
self.trail = numpy.zeros((self.cam_height, self.cam_width, 3),
numpy.uint8)
self.previous_position = None
Two options. First off, the contours are already in a Python list, so the indices of that list can be used to enumerate them. In fact you're already doing that in some sense with (i,c) in enumerate(countours). You can just use the index i to 'color' each contour with the value i drawing on a blank image, and then you'll know which contour is which just by examining the image. The other, probably better option IMO, is to use cv2.connectedComponents() to label the binary images instead of the contours of the binary image. Also pre-labeling you might try morphological operations to close up blobs.
EDIT: I follow your recommendation and I have new problems :)
Label is not persistent. When I move both contours, numbers of labels change.
Add some pictures and my code.
Hand label 0 and circle 1
Hand label 1 and circle 0
while True:
cnt += 1
if (cnt % 10) == 0:
now = time.time()
dt = now - last
fps = 10/dt
fps_smooth = (fps_smooth * smoothing) + (fps * (1.0-smoothing))
last = now
c = dev.color
cad = dev.cad
dev.wait_for_frames()
c = cv2.cvtColor(c, cv2.COLOR_RGB2GRAY)
depth = dev.depth * dev.depth_scale * 1000
print depth
#d = cv2.applyColorMap(depth.astype(np.uint8), cv2.COLORMAP_SUMMER)
print depth
res = np.float32(dev.depth)
depth = 255 * np.logical_and(depth >= 100, depth <= 500)
res2 = depth.astype(np.uint8)
kernel = np.ones((3, 3), np.uint8)
#res2 = cv2.blur(res2,(15,15))
res2 = cv2.erode(res2, kernel, iterations=4)
res2 = cv2.dilate(res2, kernel, iterations=8)
im_floodfill = res2.copy()
h, w = res2.shape[:2]
mask2 = np.zeros((h + 2, w + 2), np.uint8)
cv2.floodFill(im_floodfill, mask2, (0, 0), 255)
im_floodfill_inv = cv2.bitwise_not(im_floodfill)
im_out = res2 | im_floodfill_inv
im_out = cv2.blur(im_out,(5,5))
label = cv2.connectedComponentsWithStats(im_out)
n = label[0] - 1
cog = np.delete(label[3], 0, 0)
for i in xrange(n):
# im = cv2.circle(im,(int(cog[i][0]),int(cog[i][1])), 10, (0,0,255), -1)
cv2.putText(im_out, str(i), (int(cog[i][0]), int(cog[i][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
cv2.imshow("Depth", res)
cv2.imshow("OUT", im_out)
cv2.imshow( "C", res2)