def process_image(self, msg): try: cvim = self.bridge.imgmsg_to_cv(msg, 'bgr8') except CvBridgeError as err: rospy.logerr(e) return if self.boxes: cv.PolyLine(cvim, self.boxes, True, (0, 0, 255)) if self.selected_obj_id: cv.FillPoly(cvim, [self.boxes[self.selected_obj_id]], (0, 0, 255, 0.5)) # display object names if self.object_centers_msg: for center, color, category in zip( self.object_centers_msg.centers, self.object_centers_msg.color_labels, self.object_centers_msg.category_labels): cv.PutText(cvim, color + ' ' + category, (center.pixel.x, center.pixel.y), self.font, (0, 0, 255)) # display trajector if self.trajector_location: cv.Circle(cvim, self.trajector_location, 3, (255, 0, 0), thickness=2, lineType=cv.CV_AA, shift=0) cv.PutText(cvim, 'trajector', self.trajector_location, self.font, (255, 0, 0)) # display selected landmark if self.meaning: lmk = self.meaning.args[0] p_arr = self.lmk_geo_to_img_geo(lmk) if isinstance(lmk.representation, PointRepresentation): cv.Circle(cvim, tuple(map(int, p_arr[0])), 3, (0, 255, 0), thickness=2, lineType=cv.CV_AA, shift=0) else: pl = [[tuple(map(int, l)) for l in p_arr]] cv.PolyLine(cvim, pl, True, (0, 255, 0), thickness=3) cv.ShowImage('img', cvim) cv.WaitKey(10)
def publishBoxData(self): #Extract the characteristics of the bounding box. xl = self.br[0] xr = xl + self.br[2] yt = self.br[1] yb = yt + self.br[3] #Form the data to send left = float(xl)/self.size[0] top = float(yt)/self.size[1] right = float(xr)/self.size[0] bottom = float(yb)/self.size[1] centerX = left + (right - left)/2 centerY = bottom + (top - bottom)/2 area = 1.0*(xr-xl)*(yb-yt)/(self.size[0]*self.size[1]) #Draw a contour around the bounding box. cv.PolyLine(self.image,[[(xl,yt),(xl,yb),(xr,yb),(xr,yt)]],10, cv.RGB(0, 0, 255)) #Publish the bounding box. #Format is: "CenterX (in percent of box width) CenterY (in percent of box height) # Area (in percent of box area) LeftEdge (in percent of box width) # TopEdge (in percent of box height) RightEdge (in percent of box width) # BottomEdge (in percent of box height)" self.publisher.publish("%f %f %f %f %f %f %f" % (centerX, centerY, area, left, top, right, bottom))
def draw_subdiv_facet( img, edge ): t = edge; count = 0; # count number of edges in facet while count == 0 or t != edge: count+=1 t = cv.Subdiv2DGetEdge( t, cv.CV_NEXT_AROUND_LEFT ); buf = [] # gather points t = edge; for i in range(count): assert t>4 pt = cv.Subdiv2DEdgeOrg( t ); if not pt: break; buf.append( ( cv.Round(pt.pt[0]), cv.Round(pt.pt[1]) ) ); t = cv.Subdiv2DGetEdge( t, cv.CV_NEXT_AROUND_LEFT ); if( len(buf)==count ): pt = cv.Subdiv2DEdgeDst( cv.Subdiv2DRotateEdge( edge, 1 )); cv.FillConvexPoly( img, buf, cv.RGB(random.randrange(256),random.randrange(256),random.randrange(256)), cv.CV_AA, 0 ); cv.PolyLine( img, [buf], 1, cv.RGB(0,0,0), 1, cv.CV_AA, 0); draw_subdiv_point( img, pt.pt, cv.RGB(0,0,0));
def draw_fft(self, frame, fft_data, min_bpm, max_bpm): w = frame.width h = int(frame.height * Annotator.FFT_HEIGHT) x = 0 y = frame.height max_magnitude = max(d[1][0] for d in fft_data) def get_position(i): point_x = int(w * (float(fft_data[i][0] - min_bpm) / float(max_bpm - min_bpm))) point_y = int(y - ((h * fft_data[i][1][0]) / max_magnitude)) return point_x, point_y line = [get_position(i) for i in range(len(fft_data))] cv.PolyLine(frame, [line], False, self.get_colour()[0], 3) # Label the largest bin max_bin = max(range(len(fft_data)), key=(lambda i: fft_data[i][1][0])) x,y = get_position(max_bin) c = self.get_colour() text = "%0.1f"%fft_data[max_bin][0] cv.PutText(frame, text, (x,y), self.small_font_outline, c[1]) cv.PutText(frame, text, (x,y), self.small_font, c[0]) # Pulse ring r = Annotator.SMALL_PULSE_SIZE phase = int(((fft_data[max_bin][1][1] % (2*numpy.pi)) / numpy.pi) * 180) cv.Ellipse(frame, (int(x-(r*1.5)),int(y-r)), (int(r),int(r)), 0, 90, 90-phase, c[1], Annotator.THIN+Annotator.BORDER) cv.Ellipse(frame, (int(x-(r*1.5)),int(y-r)), (int(r),int(r)), 0, 90, 90-phase, c[0], Annotator.THIN)
def dewarp(image, window, clicked_corners): debug = cv.CloneImage(image) # draw red line around edges for debug purposes cv.PolyLine(debug, [[ clicked_corners[0], clicked_corners[1], clicked_corners[3], clicked_corners[2] ]], True, cv.RGB(0, 255, 0), 7) cv.ShowImage(window, debug) cv.WaitKey() # Assemble a rotated rectangle out of that info #rot_box = cv.MinAreaRect2(corners) enc_box = cv.BoundingRect(clicked_corners) new_corners = [(0, 0), (enc_box[2] - 1, 0), (0, enc_box[3] - 1), (enc_box[2] - 1, enc_box[3] - 1)] warp_mat = cv.CreateMat(3, 3, cv.CV_32FC1) cv.GetPerspectiveTransform(clicked_corners, new_corners, warp_mat) rotated = cv.CloneImage(image) cv.WarpPerspective(image, rotated, warp_mat) cv.ShowImage(window, rotated) cv.WaitKey(10) return rotated
def lineScan(self, image, source=None): """ Performs contour detection on a single channel image. Returns a set of 2d points containing the outer left line for the detected contours. """ storage = cv.CreateMemStorage() contours = cv.FindContours(image, storage, mode=cv.CV_RETR_EXTERNAL, method=cv.CV_CHAIN_APPROX_NONE, offset=(0, 0)) points = [] if contours: cv.DrawContours(source, contours, (0, 0, 0), (0, 0, 0), 7, -1) while contours: y_max = max([y for _, y in contours]) seq = [(x, y) for x, y in contours] i = 0 # extract only the left side of the polygon for i in range(0, len(seq) - 1): if seq[i][1] == y_max: break seq = seq[:i] if source: # draws the detected polygon line as feedback cv.PolyLine(source, [seq], False, (0, 255, 0), 1, 8, 0) points.extend(seq) contours = contours.h_next() return points
def get_finger_tips(contours, img): finger_tips = [] for ct in contours: if not ct: break x, y, r, b = find_max_rectangle(ct) # adjust ratio to at least 1/2 ratio = abs(float(y - b) / (x - r)) if ratio > 2: b = y + abs(x - r) * 2 cv.Rectangle(img, (x, y), (r, b), color.RED) # draw center rotate_center = ((x + r) / 2, y + 100) cv.Circle(img, rotate_center, 5, (255, 0, 255, 0), cv.CV_FILLED, cv.CV_AA, 0) cv.DrawContours(img, ct, color.RED, color.GREEN, 1, thickness=3) # Draw the convex hull as a closed polyline in green hull = find_convex_hull(ct) if (hull != None): cv.PolyLine(img, [hull], 1, cv.RGB(0, 255, 0), 3, cv.CV_AA) tip = find_finger_tip(hull, img) if tip != (-1, -1): finger_tips.append(tip) return finger_tips
def main(): img = cv.LoadImage("latex/Pictures/IMG_7324.CR2.jpg") img = normalize_rgb(img, aggressive=0.005) mask, seqs, time = get_mask_with_contour(img, ret_cont=True, ret_img=True, with_init_mask=False, time_took=True) boxes, min_rects = get_skin_rectangles(seqs) draw_boxes(boxes, img) center = [(c[0],c[1]) for c,_,_ in min_rects] verticies = [] for x,y,w,h in boxes: verticies+=[(x,y), (x+w,y),(x,y+h),(x+w,y+h)] # verticies = [(x+w/2, y+h/2) for x,y,w,h in boxes] polys = map(cv.BoxPoints, min_rects) cv.PolyLine(img, polys, True, cv.RGB(50,50,255), 2) sample_count = len(verticies) samples = cv.CreateMat(sample_count, 1, cv.CV_32FC2) clusters = cv.CreateMat(sample_count, 1, cv.CV_32SC1) [cv.Set1D(samples, i, verticies[i]) for i in range(sample_count)] cv.KMeans2(samples, 3, clusters, (cv.CV_TERMCRIT_EPS + cv.CV_TERMCRIT_ITER, 10, 1.0)) color = [cv.RGB(255,10,10), cv.RGB(255,255,10), cv.RGB(10,255,255), cv.RGB(255,10,255)] for i, xy in enumerate(verticies): cv.Circle(img, xy, 5, color[int(clusters[i,0])], thickness=-1) # np_centers = np.asarray(verticies) # result = cv.kmeans(verticies, 2, 0, 5, cv.CV_TERMCRIT_ITER) show_image(img)
def draw_common(points): success, center, radius = cv.MinEnclosingCircle(points) if success: cv.Circle(img, roundxy(center), cv.Round(radius), cv.CV_RGB(255, 255, 0), 1, cv.CV_AA, 0) box = cv.MinAreaRect2(points) box_vtx = [roundxy(p) for p in cv.BoxPoints(box)] cv.PolyLine(img, [box_vtx], 1, cv.CV_RGB(0, 255, 255), 1, cv.CV_AA)
def mouse_section(D): """Displays a rectangle defined by dragging the mouse.""" if D.mouse_down: x0 = D.down_coord[0] y0 = D.down_coord[1] x1 = D.up_coord[0] y1 = D.up_coord[1] cv.PolyLine(D.image, [[(x0, y0), (x0, y1), (x1, y1), (x1, y0)]], 1, cv.RGB(0, 255, 0))
def PolyLine(img, polys, is_closed, color, text=None, scale_f=1): if not DEBUG: return if scale_f != 1: polys[0] = map(lambda p: scale(p, scale_f), polys[0]) polys[0] = [(int(p[0]), int(p[1])) for p in polys[0]] cv.PolyLine(img, polys, is_closed, color) if text is not None: polys = polys[0] x, y = reduce(lambda (x, y), (w, z): (x + w, y + z), polys, (0, 0)) cv.PutText(img, text, (x / len(polys), y / len(polys)), font, (0, 255, 255))
def draw_squares( color_img, squares ): """ Squares is py list containing 4-pt numpy arrays. Step through the list and draw a polygon for each 4-group """ color, othercolor = RED, GREEN for square in squares: cv.PolyLine(color_img, [square], True, color, 3, cv.CV_AA, 0) color, othercolor = othercolor, color cv.ShowImage(WNDNAME, color_img)
def mouse_callback(self,event,u,v,flags,params): if event==cv.CV_EVENT_LBUTTONDOWN: self.first_corner = (u,v) self.drawing = True elif event==cv.CV_EVENT_LBUTTONUP: self.second_corner = (u,v) self.drawing = False elif event==cv.CV_EVENT_MOUSEMOVE and self.drawing: image2 = cv.CreateMat(self.image.height,self.image.width,cv.CV_8UC3) cv.Copy(self.image,image2) (x,y) = self.first_corner cv.PolyLine(image2,[[(x,y),(x,v),(u,v),(u,y)]],1,(255,255,255)) cv.ShowImage(self.window_name,image2)
def find_biggest_region(): """ finds all the contours in threshed image, finds the largest of those, and then marks in in the main image """ # get D so that we can change values in it global D cv.Copy(D.threshed_image, D.copy) # copy threshed image # this is OpenCV's call to find all of the contours: contours = cv.FindContours(D.copy, D.storage, cv.CV_RETR_EXTERNAL, \ cv.CV_CHAIN_APPROX_SIMPLE) # Next we want to find the *largest* contour if len(contours) > 0: biggest = contours biggestArea = cv.ContourArea(contours) while contours != None: nextArea = cv.ContourArea(contours) if biggestArea < nextArea: biggest = contours biggestArea = nextArea contours = contours.h_next() # Use OpenCV to get a bounding rectangle for the largest contour br = cv.BoundingRect(biggest, update=0) #print "in find_regions, br is", br # Example of drawing a red box # Variables: ulx ~ upper left x, lry ~ lower right y, etc. ulx = br[0] lrx = br[0] + br[2] uly = br[1] lry = br[1] + br[3] cv.PolyLine(D.image, [[(ulx, uly), (lrx, uly), (lrx, lry), (ulx, lry)]], 1, cv.RGB(255, 0, 0)) # Example of drawing a yellow circle # Variables: cenx, ceny cenx = (ulx + lrx) / 2 ceny = (uly + lry) / 2 cv.Circle(D.image, (cenx, ceny), 8, cv.RGB(255, 255, 0), thickness=1, lineType=8, shift=0)
def motion_bbox(output, motion): #global muestra, prom global bbox_list #INICIO = time.time() contour = cv.FindContours(motion, mem_storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE) bbox_list = [] #lista para almacenar los bounding box de las manchas average_box_area = 0 #variable para obtener el area en promedio de las bounding box while contour: #recorrido de los contornos/manchas bbox = cv.BoundingRect( list(contour)) #obtencion del bounding box del contorno actual pt1 = (bbox[0], bbox[1]) #punto 1 del bounding box pt2 = (bbox[0] + bbox[2], bbox[1] + bbox[3]) #punto 2 del bounding box w, h = abs(pt1[0] - pt2[0]), abs( pt1[1] - pt2[1]) #ancho y largo del bounding box #obtencion de puntos del contorno para crear un wire-frame polygon_points = cv.ApproxPoly(list(contour), mem_storage, cv.CV_POLY_APPROX_DP) #mostrar o las manchas de movimiento if SHOW_MOVEMENT_AREA: cv.FillPoly(output, [ list(polygon_points), ], cv.CV_RGB(255, 255, 255), 0, 0) #mostrar o no los contornos de las manchas de movimiento if SHOW_MOVEMENT_CONTOUR and w * h > AREA * MIN_PERCENT: cv.PolyLine(output, [ polygon_points, ], 0, cv.CV_RGB(255, 255, 255), 1, 0, 0) average_box_area += w * h #acumulacion de totales de areas bbox_list.append((pt1, pt2)) #lista con todos los bounding box contour = contour.h_next() #lectura del siguiente contorno, si hay if len(bbox_list) > 0: #si hubo movimiento average_box_area = average_box_area / float( len(bbox_list)) #area promedio de bounding box new_bbox_list = [ ] #nueva lista de bounding box, eliminando los menores al area promedio for i in range(len(bbox_list)): #recorrido de los bounding box pt1, pt2 = bbox_list[i] #separacion en dos puntos del bounding box w, h = abs(pt1[0] - pt2[0]), abs( pt1[1] - pt2[1]) #obtencion del ancho y largo if w * h >= average_box_area and w * h > AREA * MIN_PERCENT: #comparacion del area del bounding box con el promedio new_bbox_list.append( (pt1, pt2)) #si es mayor o igual, se queda en la nueva lista bbox_list = get_collided_bboxes( new_bbox_list ) #combinacion de varios bounding box en uno si estan en contacto
def drawSquares(img, squares): cpy = cv.CloneImage(img) # read 4 sequence elements at a time (all vertices of a square) i = 0 while i < squares.total: pt = [] # read 4 vertices pt.append(squares[i]) pt.append(squares[i + 1]) pt.append(squares[i + 2]) pt.append(squares[i + 3]) # draw the square as a closed polyline cv.PolyLine(cpy, [pt], 1, cv.CV_RGB(0, 255, 0), 3, cv.CV_AA, 0) i += 4 # show the resultant image cv.ShowImage(wndname, cpy)
def get_candidates(self, m_d): ''' Get candidates for this corner from new image @param m_d: marker_detector ''' # if this corner is wider then MAX_CORNER_ANGLE, we probably won't # find it anyway. Instead lets find narrow corners and calculate its # position if self.angle > MAX_CORNER_ANGLE: return [] cr = self.get_rectangle(m_d) cr = correct_rectangle(cr, m_d.size) if cr is None: return [] m_d.set_ROI(cr) tmp_img = m_d.tmp_img gray_img = m_d.gray_img bw_img = m_d.bw_img canny = m_d.canny_img cv.Copy(gray_img, tmp_img) cv.Threshold(gray_img, bw_img, 125, 255, cv.CV_THRESH_OTSU) if self.black_inside > 0: cv.Not(bw_img, bw_img) cv.Canny(gray_img, canny, 300, 500) cv.Or(bw_img, canny, bw_img) tmpim = m_d.canny_img cv.Copy(bw_img, tmpim) cv.Set2D(tmpim, 1, 1, 255) conts = cv.FindContours(tmpim, cv.CreateMemStorage(), cv.CV_RETR_EXTERNAL) cv.Zero(tmpim) m_d.set_ROI() cv.SetImageROI(tmpim, cr) result = [] while conts: aconts = cv.ApproxPoly(conts, cv.CreateMemStorage(), cv.CV_POLY_APPROX_DP, 2) nconts = list(aconts) cv.PolyLine(tmpim, [nconts], True, (255, 255, 255)) self._append_candidates_from_conts(cr, result, nconts, m_d) conts = conts.h_next() # print result # db.show([tmpim,m_d.draw_img], 'tmpim', 0, 0, 0) return result
def getAnnotatedImage(self, showRects=True, showContours=False, showConvexHulls=False, showFlow=False): ''' @return: the annotation image with selected objects drawn upon it. showFlow will only work if the BG subtraction method was MCFD. @note: You must call detect() prior to getAnnotatedImage() to see updated results. ''' rects = self.getRects() outImg = self._annotateImg.copy( ) #deep copy, so can freely modify the copy if outImg == None: return None #draw optical flow information in white if showFlow and (self._method == pv.BG_SUBTRACT_MCFD): flow = self._bgSubtract.getOpticalFlow() flow.annotateFrame(outImg) if showContours or showConvexHulls: cvimg = outImg.asOpenCV() #draw contours in green if showContours: cv.DrawContours(cvimg, self._contours, cv.RGB(0, 255, 0), cv.RGB(255, 0, 0), 2) #draw hulls in cyan if showConvexHulls: cv.PolyLine(cvimg, self._convexHulls, True, cv.RGB(0, 255, 255)) #draw bounding box in yellow if showRects: for r in rects: outImg.annotateRect(r, "yellow") return outImg
if __name__ == '__main__': img = cv.CreateImage((100, 100), 8, 1) a = (50, -10) b = (85, 50) c = (50, 90) d = (5, 50) cv.FillConvexPoly(img, [a, b, c, d], (255, 255, 255)) temp = 'temp' cv.NamedWindow(temp) oa, ob, oc, od = (48, -8), (80, 50), (48, 88), (0, 50) points = [oa, ob, oc, od] corners = [Corner(points, 0), Corner(points, 1), Corner(points, 2), Corner(points, 3)] CP = CornerPredictor(corners, 50, img) cv.PolyLine(img, [[oa, ob, oc, od]], 1, (150, 100, 100)) dimg = cv.CreateImage((200, 200), 8, 1) cv.PyrUp(img, dimg) cv.ShowImage(temp, dimg) cv.WaitKey(10000)
def show(self): """ Process and show the current frame """ source = cv.LoadImage(self.files[self.index]) width, height = cv.GetSize(source) center = (width / 2) + self.offset cv.Line(source, (center, 0), (center, height), (0, 255, 0), 1) if self.roi: x, y, a, b = self.roi print self.roi width, height = ((a - x), (b - y)) mask = cv.CreateImage((width, height), cv.IPL_DEPTH_8U, 1) cv.SetImageROI(source, (x, y, width, height)) cv.Split(source, None, None, mask, None) gray = cv.CloneImage(mask) cv.InRangeS(mask, self.thresholdMin, self.thresholdMax, mask) cv.And(mask, gray, gray) line = [] points = [] for i in range(0, height - 1): row = cv.GetRow(gray, i) minVal, minLoc, maxLoc, maxVal = cv.MinMaxLoc(row) y = i x = maxVal[0] point = (0, 0, height - i) if x > 0: line.append((x, y)) s = x / sin(radians(self.camAngle)) x = s * cos(self.angles[self.index]) z = height - y y = s * sin(self.angles[self.index]) point = (round(x, 2), round(y, 2), z) points.append(point) cv.PolyLine(source, [line], False, (255, 0, 0), 2, 8) cv.ResetImageROI(source) x, y, a, b = self.roi cv.Rectangle(source, (int(x), int(y)), (int(a), int(b)), (255.0, 255, 255, 0)) if self.roi: x, y, a, b = self.roi width, height = ((a - x), (b - y)) mask = cv.CreateImage((width, height), cv.IPL_DEPTH_8U, 1) cv.SetImageROI( source, (x - width, y, width, height)) # moves roi to the left cv.Split(source, None, None, mask, None) gray = cv.CloneImage(mask) cv.InRangeS(mask, self.thresholdMin, self.thresholdMax, mask) cv.And(mask, gray, gray) line = [] points2 = [] for i in range(0, height - 1): row = cv.GetRow(gray, i) minVal, minLoc, maxLoc, maxVal = cv.MinMaxLoc(row) y = i x = maxVal[0] point = (0, 0, height - i) if x > 0: line.append((x, y)) x = width - x # left to the x-axis s = x / sin(radians(self.camAngle)) x = s * cos(self.angles[self.index]) z = height - y # 500 higher then the other. y = s * sin(self.angles[self.index]) a = radians(300) nx = (cos(a) * x) - (sin(a) * y) ny = (sin(a) * x) + (cos(a) * y) point = (nx, ny, z) points2.append(point) cv.PolyLine(source, [line], False, (255, 0, 0), 2, 8) cv.ResetImageROI(source) x, y, a, b = self.roi cv.Rectangle(source, (int(x), int(y)), (int(a), int(b)), (255.0, 255, 255, 0)) if self.mode == 'mask': cv.ShowImage('preview', mask) return if self.mode == 'record' and self.roi: font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 1) cv.PutText(source, "recording %d" % self.index, (20, 20), font, (0, 0, 255)) self.points.extend(points) self.points2.extend(points2) #self.colors.extend(colors); cv.ShowImage('preview', source)
cv.Set(temp, cv.RGB(0, 0, 0)) cv.WarpAffine(src, temp, map) cv.Or(temp, bg, bg) cv.ShowImage("comp", bg) scribble = cv.CloneMat(bg) if 0: for i in range(10): df.find(bg) for (sym, coords) in df.find(bg).items(): print sym cv.PolyLine(scribble, [coords], 1, cv.CV_RGB(255, 0, 0), 1, lineType=cv.CV_AA) Xs = [x for (x, y) in coords] Ys = [y for (x, y) in coords] where = ((min(Xs) + max(Xs)) / 2, max(Ys) - 50) cv.PutText(scribble, sym, where, font, cv.RGB(0, 255, 0)) cv.ShowImage("results", scribble) cv.WaitKey() sys.exit(0) capture = cv.CaptureFromCAM(0) while True: img = cv.QueryFrame(capture)
def draw_hull(self, im, rgb=(0, 255, 0)): cv.PolyLine(im, [self.hull], 1, cv.RGB(*rgb), 1, cv.CV_AA)
def find_biggest_region(D): """ finds all the contours in threshed image, finds the largest of those, and then marks in in the main image """ # Create a copy image of thresholds then find contours on that image storage = cv.CreateMemStorage(0) # Create memory storage for contours copy = cv.CreateImage(D.size, 8, 1) cv.Copy(D.threshed_image, copy) # copy threshed image # this is OpenCV's call to find all of the contours: contours = cv.FindContours(copy, storage, cv.CV_RETR_EXTERNAL, \ cv.CV_CHAIN_APPROX_SIMPLE) # Next we want to find the *largest* contour if len(contours) > 0: biggest = contours biggestArea = cv.ContourArea(contours) while contours != None: nextArea = cv.ContourArea(contours) if biggestArea < nextArea: biggest = contours biggestArea = nextArea contours = contours.h_next() # Use OpenCV to get a bounding rectangle for the largest contour br = cv.BoundingRect(biggest, update=0) #print "in find_regions, br is", br ulx, uly, width, height = br[0], br[1], br[2], br[3] D.br = (ulx, uly), (width, height) D.target_size = width * height # You will want to change these so that they draw a box # around the largest contour and a circle at its center: # Example of drawing a yellow box cv.PolyLine(D.image, [[(ulx,uly), (ulx+width,uly), (ulx+width,uly+height),\ (ulx,uly+height)]], 1, cv.RGB(255, 255, 0)) # Draw circle in the center of the target cv.Circle(D.image, (ulx+width/2,uly+height/2), 10, \ cv.RGB(255, 0, 0), thickness=1, lineType=8, shift=0) # Draw the contours in white with inner ones in green cv.DrawContours(D.image, biggest, cv.RGB(255, 255, 255), \ cv.RGB(0, 255, 0), 1, thickness=2, lineType=8, \ offset=(0,0)) # Reset coordinates to keep track of where the center of the coutour is D.last_target_coord = D.target_coord D.target_coord = (ulx + width / 2, uly - height / 2) D.p1, D.p2, D.p3, D.p4 = (D.target_coord[0],D.target_coord[1] + height/2),\ (D.target_coord[0],D.target_coord[1] + height/2), \ (D.target_coord[0],D.target_coord[1] + height/2), \ (D.target_coord[0],D.target_coord[1] + height/2) else: D.br = (0, 0), (0, 0) D.target_size = 0 D.p1, D.p2, D.p3, D.p4 = (0, 0), (0, 0), (0, 0), (0, 0)
def find_regions(self): #Create a copy image of thresholds then find contours on that image storage = cv.CreateMemStorage(0) storage1 = cv.CreateMemStorage(0) copy = cv.CreateImage(self.size, 8, 1) cv.Copy(self.threshold, copy) contours = cv.FindContours(copy, storage, cv.CV_RETR_EXTERNAL,\ cv.CV_CHAIN_APPROX_SIMPLE) #Find the largest contour if len(contours) > 0: biggest = contours biggestArea = cv.ContourArea(contours) while contours != None: nextArea = cv.ContourArea(contours) if biggestArea < nextArea: biggest = contours biggestArea = nextArea contours = contours.h_next() #print biggest # after_biggest = biggest.h_next() # after_biggest = None #Get a bounding rectangle for the largest contour br = cv.BoundingRect(biggest, update=0) #self.tree = cv.CreateContourTree(biggest, storage1, 0) #print self.contour_tree #Find the middle of it circle_x = br[0] + br[2] / 2 circle_y = br[1] + br[3] / 2 #Create a blob message and publish it. # blob = Blob( br[0], br[1], br[2], br[3], circle_x, circle_y) # self.publish(blob) #Find the coordinates for each corner of the box box_tl = (br[0], br[1]) box_tr = (br[0] + br[2], br[1]) box_bl = (br[0], br[1] + br[3]) box_br = (br[0] + br[2], br[1] + br[3]) #Draw the box cv.PolyLine(self.image,[[box_tl, box_bl, box_br, box_tr]],\ 1, cv.RGB(255, 0, 0)) #Draw the circle cv.Circle(self.image,(circle_x, circle_y), 10, cv.RGB(255, 0, 0),\ thickness=1, lineType=8, shift=0) #Draw the contours cv.DrawContours(self.image, biggest, cv.RGB(255, 255, 255), cv.RGB(0, 255, 0), 1, thickness=2, lineType=8, offset=(0, 0))
def run(self): global centroid frame = cv.QueryFrame(self.capture) while not frame: cv.WaitKey(10) frame = cv.QueryFrame(self.capture) frame_size = cv.GetSize(frame) # Capture the first frame from webcam for image properties display_image = cv.QueryFrame(self.capture) while not display_image: cv.WaitKey(10) display_image = cv.QueryFrame(self.capture) # Greyscale image, thresholded to create the motion mask: grey_image = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 1) # The RunningAvg() function requires a 32-bit or 64-bit image... running_average_image = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_32F, 3) # ...but the AbsDiff() function requires matching image depths: running_average_in_display_color_depth = cv.CloneImage(display_image) # RAM used by FindContours(): mem_storage = cv.CreateMemStorage(0) # The difference between the running average and the current frame: difference = cv.CloneImage(display_image) target_count = 1 last_target_count = 1 last_target_change_t = 0.0 k_or_guess = 1 codebook = [] frame_count = 0 last_frame_entity_list = [] t0 = time.time() # For toggling display: image_list = ["camera", "difference", "threshold", "display", "faces"] image_index = 0 # Index into image_list # Prep for text drawing: text_font = cv.InitFont(cv.CV_FONT_HERSHEY_COMPLEX, .5, .5, 0.0, 1, cv.CV_AA) text_coord = (5, 15) text_color = cv.CV_RGB(255, 255, 255) ############################### ### Face detection stuff haar_cascade = cv.Load('haarcascades/haarcascade_frontalface_alt.xml') # Set this to the max number of targets to look for (passed to k-means): max_targets = 3 while True: # Capture frame from webcam camera_image = cv.QueryFrame(self.capture) while not camera_image: cv.WaitKey(10) camera_image = cv.QueryFrame(self.capture) frame_count += 1 print 'frame_count = ', frame_count frame_t0 = time.time() # Create an image with interactive feedback: display_image = cv.CloneImage(camera_image) # Create a working "color image" to modify / blur color_image = cv.CloneImage(display_image) # Smooth to get rid of false positives cv.Smooth(color_image, color_image, cv.CV_GAUSSIAN, 19, 0) # Use the Running Average as the static background # a = 0.020 leaves artifacts lingering way too long. # a = 0.320 works well at 320x240, 15fps. (1/a is roughly num frames.) cv.RunningAvg(color_image, running_average_image, 0.320, None) # Convert the scale of the moving average. cv.ConvertScale(running_average_image, running_average_in_display_color_depth, 1.0, 0.0) # Subtract the current frame from the moving average. cv.AbsDiff(color_image, running_average_in_display_color_depth, difference) # Convert the image to greyscale. cv.CvtColor(difference, grey_image, cv.CV_RGB2GRAY) # Threshold the image to a black and white motion mask: cv.Threshold(grey_image, grey_image, 2, 255, cv.CV_THRESH_BINARY) # Smooth and threshold again to eliminate "sparkles" cv.Smooth(grey_image, grey_image, cv.CV_GAUSSIAN, 19, 0) cv.Threshold(grey_image, grey_image, 240, 255, cv.CV_THRESH_BINARY) grey_image_as_array = numpy.asarray(cv.GetMat(grey_image)) non_black_coords_array = numpy.where(grey_image_as_array > 3) # Convert from numpy.where()'s two separate lists to one list of (x, y) tuples: non_black_coords_array = zip(non_black_coords_array[1], non_black_coords_array[0]) points = [ ] # Was using this to hold either pixel coords or polygon coords. bounding_box_list = [] # Now calculate movements using the white pixels as "motion" data contour = cv.FindContours(grey_image, mem_storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE) while contour: bounding_rect = cv.BoundingRect(list(contour)) point1 = (bounding_rect[0], bounding_rect[1]) point2 = (bounding_rect[0] + bounding_rect[2], bounding_rect[1] + bounding_rect[3]) bounding_box_list.append((point1, point2)) polygon_points = cv.ApproxPoly(list(contour), mem_storage, cv.CV_POLY_APPROX_DP) # To track polygon points only (instead of every pixel): #points += list(polygon_points) # Draw the contours: ###cv.DrawContours(color_image, contour, cv.CV_RGB(255,0,0), cv.CV_RGB(0,255,0), levels, 3, 0, (0,0) ) cv.FillPoly(grey_image, [ list(polygon_points), ], cv.CV_RGB(255, 255, 255), 0, 0) cv.PolyLine(display_image, [ polygon_points, ], 0, cv.CV_RGB(255, 255, 255), 1, 0, 0) #cv.Rectangle( display_image, point1, point2, cv.CV_RGB(120,120,120), 1) contour = contour.h_next() # Find the average size of the bbox (targets), then # remove any tiny bboxes (which are prolly just noise). # "Tiny" is defined as any box with 1/10th the area of the average box. # This reduces false positives on tiny "sparkles" noise. box_areas = [] for box in bounding_box_list: box_width = box[right][0] - box[left][0] box_height = box[bottom][0] - box[top][0] box_areas.append(box_width * box_height) #cv.Rectangle( display_image, box[0], box[1], cv.CV_RGB(255,0,0), 1) average_box_area = 0.0 if len(box_areas): average_box_area = float(sum(box_areas)) / len(box_areas) trimmed_box_list = [] for box in bounding_box_list: box_width = box[right][0] - box[left][0] box_height = box[bottom][0] - box[top][0] # Only keep the box if it's not a tiny noise box: if (box_width * box_height) > average_box_area * 0.1: trimmed_box_list.append(box) # Draw the trimmed box list: bounding_box_list = merge_collided_bboxes(trimmed_box_list) # Draw the merged box list: for box in bounding_box_list: cv.Rectangle(display_image, box[0], box[1], cv.CV_RGB(0, 255, 0), 1) # Here are our estimate points to track, based on merged & trimmed boxes: estimated_target_count = len(bounding_box_list) # Don't allow target "jumps" from few to many or many to few. # Only change the number of targets up to one target per n seconds. # This fixes the "exploding number of targets" when something stops moving # and the motion erodes to disparate little puddles all over the place. if frame_t0 - last_target_change_t < .350: # 1 change per 0.35 secs estimated_target_count = last_target_count else: if last_target_count - estimated_target_count > 1: estimated_target_count = last_target_count - 1 if estimated_target_count - last_target_count > 1: estimated_target_count = last_target_count + 1 last_target_change_t = frame_t0 # Clip to the user-supplied maximum: estimated_target_count = min(estimated_target_count, max_targets) # The estimated_target_count at this point is the maximum number of targets # we want to look for. If kmeans decides that one of our candidate # bboxes is not actually a target, we remove it from the target list below. # Using the numpy values directly (treating all pixels as points): points = non_black_coords_array center_points = [] if len(points): # If we have all the "target_count" targets from last frame, # use the previously known targets (for greater accuracy). k_or_guess = max(estimated_target_count, 1) # Need at least one target to look for. if len(codebook) == estimated_target_count: k_or_guess = codebook #points = vq.whiten(array( points )) # Don't do this! Ruins everything. codebook, distortion = vq.kmeans(array(points), k_or_guess) # Convert to tuples (and draw it to screen) for center_point in codebook: center_point = (int(center_point[0]), int(center_point[1])) center_points.append(center_point) #cv.Circle(display_image, center_point, 10, cv.CV_RGB(255, 0, 0), 2) #cv.Circle(display_image, center_point, 5, cv.CV_RGB(255, 0, 0), 3) # Now we have targets that are NOT computed from bboxes -- just # movement weights (according to kmeans). If any two targets are # within the same "bbox count", average them into a single target. # # (Any kmeans targets not within a bbox are also kept.) trimmed_center_points = [] removed_center_points = [] for box in bounding_box_list: # Find the centers within this box: center_points_in_box = [] for center_point in center_points: if center_point[0] < box[right][0] and center_point[0] > box[left][0] and \ center_point[1] < box[bottom][1] and center_point[1] > box[top][1] : # This point is within the box. center_points_in_box.append(center_point) # Now see if there are more than one. If so, merge them. if len(center_points_in_box) > 1: # Merge them: x_list = y_list = [] for point in center_points_in_box: x_list.append(point[0]) y_list.append(point[1]) average_x = int(float(sum(x_list)) / len(x_list)) average_y = int(float(sum(y_list)) / len(y_list)) trimmed_center_points.append((average_x, average_y)) # Record that they were removed: removed_center_points += center_points_in_box if len(center_points_in_box) == 1: trimmed_center_points.append( center_points_in_box[0]) # Just use it. # If there are any center_points not within a bbox, just use them. # (It's probably a cluster comprised of a bunch of small bboxes.) for center_point in center_points: if (not center_point in trimmed_center_points) and ( not center_point in removed_center_points): trimmed_center_points.append(center_point) # Determine if there are any new (or lost) targets: actual_target_count = len(trimmed_center_points) last_target_count = actual_target_count # Now build the list of physical entities (objects) this_frame_entity_list = [] # An entity is list: [ name, color, last_time_seen, last_known_coords ] for target in trimmed_center_points: # Is this a target near a prior entity (same physical entity)? entity_found = False entity_distance_dict = {} for entity in last_frame_entity_list: entity_coords = entity[3] delta_x = entity_coords[0] - target[0] delta_y = entity_coords[1] - target[1] distance = sqrt(pow(delta_x, 2) + pow(delta_y, 2)) entity_distance_dict[distance] = entity # Did we find any non-claimed entities (nearest to furthest): distance_list = entity_distance_dict.keys() distance_list.sort() for distance in distance_list: # Yes; see if we can claim the nearest one: nearest_possible_entity = entity_distance_dict[distance] # Don't consider entities that are already claimed: if nearest_possible_entity in this_frame_entity_list: #print "Target %s: Skipping the one iwth distance: %d at %s, C:%s" % (target, distance, nearest_possible_entity[3], nearest_possible_entity[1] ) continue #print "Target %s: USING the one iwth distance: %d at %s, C:%s" % (target, distance, nearest_possible_entity[3] , nearest_possible_entity[1]) # Found the nearest entity to claim: entity_found = True nearest_possible_entity[ 2] = frame_t0 # Update last_time_seen nearest_possible_entity[ 3] = target # Update the new location this_frame_entity_list.append(nearest_possible_entity) #log_file.write( "%.3f MOVED %s %d %d\n" % ( frame_t0, nearest_possible_entity[0], nearest_possible_entity[3][0], nearest_possible_entity[3][1] ) ) break if entity_found == False: # It's a new entity. color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) name = hashlib.md5(str(frame_t0) + str(color)).hexdigest()[:6] last_time_seen = frame_t0 new_entity = [name, color, last_time_seen, target] this_frame_entity_list.append(new_entity) #log_file.write( "%.3f FOUND %s %d %d\n" % ( frame_t0, new_entity[0], new_entity[3][0], new_entity[3][1] ) ) # Now "delete" any not-found entities which have expired: entity_ttl = 1.0 # 1 sec. for entity in last_frame_entity_list: last_time_seen = entity[2] if frame_t0 - last_time_seen > entity_ttl: # It's gone. #log_file.write( "%.3f STOPD %s %d %d\n" % ( frame_t0, entity[0], entity[3][0], entity[3][1] ) ) pass else: # Save it for next time... not expired yet: this_frame_entity_list.append(entity) # For next frame: last_frame_entity_list = this_frame_entity_list # Draw the found entities to screen: for entity in this_frame_entity_list: center_point = entity[3] c = entity[1] # RGB color tuple cv.Circle(display_image, center_point, 20, cv.CV_RGB(c[0], c[1], c[2]), 1) cv.Circle(display_image, center_point, 15, cv.CV_RGB(c[0], c[1], c[2]), 1) cv.Circle(display_image, center_point, 10, cv.CV_RGB(c[0], c[1], c[2]), 2) cv.Circle(display_image, center_point, 5, cv.CV_RGB(c[0], c[1], c[2]), 3) #print "min_size is: " + str(min_size) # Listen for ESC or ENTER key c = cv.WaitKey(7) % 0x100 if c == 27 or c == 10: break # Toggle which image to show if chr(c) == 'd': image_index = (image_index + 1) % len(image_list) image_name = image_list[image_index] image_name = "display" # for black and white: Threshold #for colored = display # Display frame to user if image_name == "camera": image = camera_image cv.PutText(image, "Camera (Normal)", text_coord, text_font, text_color) elif image_name == "difference": image = difference cv.PutText(image, "Difference Image", text_coord, text_font, text_color) elif image_name == "display": image = display_image cv.PutText(image, "Targets (w/AABBs and contours)", text_coord, text_font, text_color) elif image_name == "threshold": # Convert the image to color. cv.CvtColor(grey_image, display_image, cv.CV_GRAY2RGB) image = display_image # Re-use display image here cv.PutText(image, "Motion Mask", text_coord, text_font, text_color) elif image_name == "faces": # Do face detection detect_faces(camera_image, haar_cascade, mem_storage) image = camera_image # Re-use camera image here cv.PutText(image, "Face Detection", text_coord, text_font, text_color) cv.ShowImage("Target", image) if self.writer: cv.WriteFrame(self.writer, image) arr = numpy.asarray(image[:, :]) move_thresh = 100 counter = 0 # If only using a camera, then there is no time.sleep() needed, # because the camera clips us to 15 fps. But if reading from a file, # we need this to keep the time-based target clipping correct: frame_t1 = time.time() centroid = get_centroid(trimmed_center_points) print 'centroid = ', centroid # If reading from a file, put in a forced delay: if not self.writer: delta_t = frame_t1 - frame_t0 if delta_t < (1.0 / 15.0): time.sleep((1.0 / 15.0) - delta_t) t1 = time.time() time_delta = t1 - t0 processed_fps = float(frame_count) / time_delta print "Got %d frames. %.1f s. %f fps." % (frame_count, time_delta, processed_fps)
def detect_motion(self, sensitivity='medium'): #Finding Video Size from the first frame frame = cv.QueryFrame(self.video_handle) frame_size = cv.GetSize(frame) '''Initializing Image Variables(to be used in motion detection) with required types and sizes''' # Image containg instantaneous moving rectangles color_image = cv.CreateImage(frame_size, 8, 3) # Resizing to window size color_output = cv.CreateImage(self.window_size, 8, 3) # Grey Image used for contour detection grey_image = cv.CreateImage(frame_size, cv.IPL_DEPTH_8U, 1) # Image storing background (moving pixels are averaged over small time window) moving_average = cv.CreateImage(frame_size, cv.IPL_DEPTH_32F, 3) # Image for storing tracks resized to window size track_output = cv.CreateImage(self.window_size, cv.IPL_DEPTH_8U, 3) track_image, track_win = self.init_track_window(frame) def totuple(a): try: return tuple(totuple(i) for i in a) except TypeError: return a first = True # Infinite loop for continuous detection of motion while True: '''########## Pixelwise Detection of Motion in a frame ###########''' # Capturing Frame color_image = cv.QueryFrame(self.video_handle) ##### Sensitivity Control 1 ##### if (sensitivity == 'medium') or (sensitivity == 'low'): # Gaussian Smoothing cv.Smooth(color_image, color_image, cv.CV_GAUSSIAN, 3, 0) if first: difference = cv.CloneImage(color_image) temp = cv.CloneImage(color_image) cv.ConvertScale(color_image, moving_average, 1.0, 0.0) first = False else: cv.RunningAvg(color_image, moving_average, .020, None) # Convert the scale of the moving average. cv.ConvertScale(moving_average, temp, 1, 0.0) # Minus the current frame from the moving average. cv.AbsDiff(color_image, temp, difference) #cv.ShowImage("BG",difference) # Convert the image to grayscale. cv.CvtColor(difference, grey_image, cv.CV_RGB2GRAY) ##### Sensitivity Control 2 ##### sens_thres = 90 if (sensitivity == 'low') or (self.opt == 'cam') else 40 # Convert the image to black and white. cv.Threshold(grey_image, grey_image, sens_thres, 255, cv.CV_THRESH_BINARY) '''### Blobing moved adjacent pixels, finding closed contours and bounding rectangles ###''' ##### Sensitivity Control 3 ##### if (sensitivity == 'medium') or (sensitivity == 'low'): # Dilate and erode to get people blobs ker_size = 20 if self.opt == 'file' else 50 cv.Dilate(grey_image, grey_image, None, ker_size) cv.Erode(grey_image, grey_image, None, 3) storage = cv.CreateMemStorage(0) contour = cv.FindContours(grey_image, storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE) points = [] while contour: bound_rect = cv.BoundingRect(list(contour)) polygon_points = cv.ApproxPoly(list(contour), storage, cv.CV_POLY_APPROX_DP) pt1 = (bound_rect[0], bound_rect[1]) pt2 = (bound_rect[0] + bound_rect[2], bound_rect[1] + bound_rect[3]) if (self.opt == 'file'): points.append(pt1) points.append(pt2) elif (bound_rect[0] - bound_rect[2] > 20) and (bound_rect[1] - bound_rect[3] > 20): points.append(pt1) points.append(pt2) box = cv.MinAreaRect2(polygon_points) box2 = cv.BoxPoints(box) box3 = np.int0(np.around(box2)) box4 = totuple(box3) box5 = box4 + (box4[0], ) # Filling the contours in the greyscale image (visual blobs instead of just contours) cv.FillPoly(grey_image, [ list(polygon_points), ], cv.CV_RGB(255, 255, 255), 0, 0) # Following line to draw detected contours as well #cv.PolyLine( color_image, [ polygon_points, ], 0, cv.CV_RGB(255,0,0), 1, 0, 0 ) # Drawing Rectangle around the detected contour cv.PolyLine(color_image, [list(box5)], 0, (0, 255, 255), 2) if len(points): # (self.opt == 'file') and center1 = (pt1[0] + pt2[0]) / 2 center2 = (pt1[1] + pt2[1]) / 2 cv.Circle(color_image, (center1, center2), 5, cv.CV_RGB(0, 255, 0), -1) rad = 3 if self.opt == 'file' else 5 cv.Circle(track_image, (center1, center2), rad, cv.CV_RGB(255, 128, 0), -1) contour = contour.h_next() # Uncomment to track centroid of all the moved boxes (only for WebCam) ''' if (self.opt == 'cam') and len(points): center_point = reduce(lambda a, b: ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2), points) cv.Circle(track_image, center_point, 15, cv.CV_RGB(255, 128, 0), -1) ''' cv.Resize(color_image, color_output, cv.CV_INTER_AREA) cv.ShowImage("Original", color_output) cv.Resize(track_image, track_output, cv.CV_INTER_AREA) cv.ShowImage(track_win, track_output) # Listen for ESC key c = cv.WaitKey(7) % 0x100 if (0xFF & c == 27): cv.SaveImage('Tracks_img_042_' + sensitivity + '.jpeg', track_output) break
def run(self): frame = cv.QueryFrame(self.capture) frame_size = cv.GetSize(frame) # Capture the first frame from webcam for image properties display_image = cv.QueryFrame(self.capture) # Greyscale image, thresholded to create the motion mask: grey_image = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 1) # The RunningAvg() function requires a 32-bit or 64-bit image... running_average_image = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_32F, 3) # ...but the AbsDiff() function requires matching image depths: running_average_in_display_color_depth = cv.CloneImage(display_image) # RAM used by FindContours(): mem_storage = cv.CreateMemStorage(0) # The difference between the running average and the current frame: difference = cv.CloneImage(display_image) target_count = 1 last_target_count = 1 last_target_change_t = 0.0 k_or_guess = 1 codebook = [] frame_count = 0 last_frame_entity_list = [] t0 = time.time() # For toggling display: image_list = ["display", "difference", "threshold", "camera", "faces"] image_index = 0 # Index into image_list # Prep for text drawing: text_font = cv.InitFont(cv.CV_FONT_HERSHEY_COMPLEX, .5, .5, 0.0, 1, cv.CV_AA) text_coord = (5, 15) text_color = cv.CV_RGB(255, 255, 255) haar_cascade = cv.Load( '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml' ) max_targets = 3 while True: camera_image = cv.QueryFrame(self.capture) frame_count += 1 frame_t0 = time.time() # Create an image with interactive feedback: display_image = cv.CloneImage(camera_image) # Create a working "color image" to modify / blur color_image = cv.CloneImage(display_image) # Smooth to get rid of false positives cv.Smooth(color_image, color_image, cv.CV_GAUSSIAN, 19, 0) # Use the Running Average as the static background # a = 0.020 leaves artifacts lingering way too long. # a = 0.320 works well at 320x240, 15fps. (1/a is roughly num frames.) cv.RunningAvg(color_image, running_average_image, 0.420, None) # Convert the scale of the moving average. cv.ConvertScale(running_average_image, running_average_in_display_color_depth, 1.0, 0.0) # Subtract the current frame from the moving average. cv.AbsDiff(color_image, running_average_in_display_color_depth, difference) # Convert the image to greyscale. cv.CvtColor(difference, grey_image, cv.CV_RGB2GRAY) # Threshold the image to a black and white motion mask: cv.Threshold(grey_image, grey_image, 2, 255, cv.CV_THRESH_BINARY) # Smooth and threshold again to eliminate "sparkles" cv.Smooth(grey_image, grey_image, cv.CV_GAUSSIAN, 19, 0) cv.Threshold(grey_image, grey_image, 240, 255, cv.CV_THRESH_BINARY) cv.Dilate(grey_image, grey_image, None, 18) cv.Erode(grey_image, grey_image, None, 20) grey_image_as_array = numpy.asarray(cv.GetMat(grey_image)) non_black_coords_array = numpy.where(grey_image_as_array > 3) # Convert from numpy.where()'s two separate lists to one list of (x, y) tuples: non_black_coords_array = zip(non_black_coords_array[1], non_black_coords_array[0]) points = [ ] # Was using this to hold either pixel coords or polygon coords. bounding_box_list = [] # Now calculate movements using the white pixels as "motion" data contour = cv.FindContours(grey_image, mem_storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE) while contour: bounding_rect = cv.BoundingRect(list(contour)) point1 = (bounding_rect[0], bounding_rect[1]) point2 = (bounding_rect[0] + bounding_rect[2], bounding_rect[1] + bounding_rect[3]) bounding_box_list.append((point1, point2)) polygon_points = cv.ApproxPoly(list(contour), mem_storage, cv.CV_POLY_APPROX_DP) # To track polygon points only (instead of every pixel): #points += list(polygon_points) # Draw the contours: levels = 0 cv.DrawContours(color_image, contour, cv.CV_RGB(255, 0, 0), cv.CV_RGB(0, 255, 0), levels, 3, 0, (0, 0)) cv.FillPoly(grey_image, [ list(polygon_points), ], cv.CV_RGB(255, 255, 255), 0, 0) cv.PolyLine(display_image, [ polygon_points, ], 0, cv.CV_RGB(255, 255, 255), 1, 0, 0) #cv.Rectangle( display_image, point1, point2, cv.CV_RGB(120,120,120), 1) contour = contour.h_next() # Find the average size of the bbox (targets), then # remove any tiny bboxes (which are prolly just noise). # "Tiny" is defined as any box with 1/10th the area of the average box. # This reduces false positives on tiny "sparkles" noise. box_areas = [] for box in bounding_box_list: box_width = box[right][0] - box[left][0] box_height = box[bottom][0] - box[top][0] box_areas.append(box_width * box_height) #cv.Rectangle( display_image, box[0], box[1], cv.CV_RGB(255,0,0), 1) average_box_area = 0.0 if len(box_areas): average_box_area = float(sum(box_areas)) / len(box_areas) trimmed_box_list = [] for box in bounding_box_list: box_width = box[right][0] - box[left][0] box_height = box[bottom][0] - box[top][0] # Only keep the box if it's not a tiny noise box: if (box_width * box_height) > average_box_area * 0.1: trimmed_box_list.append(box) # Draw the trimmed box list: #for box in trimmed_box_list: # cv.Rectangle( display_image, box[0], box[1], cv.CV_RGB(0,255,0), 2 ) bounding_box_list = merge_collided_bboxes(trimmed_box_list) # Draw the merged box list: for box in bounding_box_list: cv.Rectangle(display_image, box[0], box[1], cv.CV_RGB(0, 255, 0), 1) # Here are our estimate points to track, based on merged & trimmed boxes: estimated_target_count = len(bounding_box_list) if frame_t0 - last_target_change_t < .650: # 1 change per 0.35 secs estimated_target_count = last_target_count else: if last_target_count - estimated_target_count > 1: estimated_target_count = last_target_count - 1 if estimated_target_count - last_target_count > 1: estimated_target_count = last_target_count + 1 last_target_change_t = frame_t0 # Clip to the user-supplied maximum: estimated_target_count = min(estimated_target_count, max_targets) points = non_black_coords_array center_points = [] if len(points): k_or_guess = max(estimated_target_count, 1) # Need at least one target to look for. if len(codebook) == estimated_target_count: k_or_guess = codebook #points = vq.whiten(array( points )) # Don't do this! Ruins everything. codebook, distortion = vq.kmeans(array(points), k_or_guess) # Convert to tuples (and draw it to screen) for center_point in codebook: center_point = (int(center_point[0]), int(center_point[1])) center_points.append(center_point) trimmed_center_points = [] removed_center_points = [] for box in bounding_box_list: # Find the centers within this box: center_points_in_box = [] for center_point in center_points: if center_point[0] < box[right][0] and center_point[0] > box[left][0] and \ center_point[1] < box[bottom][1] and center_point[1] > box[top][1] : # This point is within the box. center_points_in_box.append(center_point) # Now see if there are more than one. If so, merge them. if len(center_points_in_box) > 1: # Merge them: x_list = y_list = [] for point in center_points_in_box: x_list.append(point[0]) y_list.append(point[1]) average_x = int(float(sum(x_list)) / len(x_list)) average_y = int(float(sum(y_list)) / len(y_list)) trimmed_center_points.append((average_x, average_y)) # Record that they were removed: removed_center_points += center_points_in_box if len(center_points_in_box) == 1: trimmed_center_points.append( center_points_in_box[0]) # Just use it. # If there are any center_points not within a bbox, just use them. # (It's probably a cluster comprised of a bunch of small bboxes.) for center_point in center_points: if (not center_point in trimmed_center_points) and ( not center_point in removed_center_points): trimmed_center_points.append(center_point) # Determine if there are any new (or lost) targets: actual_target_count = len(trimmed_center_points) last_target_count = actual_target_count # Now build the list of physical entities (objects) this_frame_entity_list = [] # An entity is list: [ name, color, last_time_seen, last_known_coords ] for target in trimmed_center_points: # Is this a target near a prior entity (same physical entity)? entity_found = False entity_distance_dict = {} for entity in last_frame_entity_list: entity_coords = entity[3] delta_x = entity_coords[0] - target[0] delta_y = entity_coords[1] - target[1] distance = sqrt(pow(delta_x, 2) + pow(delta_y, 2)) entity_distance_dict[distance] = entity # Did we find any non-claimed entities (nearest to furthest): distance_list = entity_distance_dict.keys() distance_list.sort() for distance in distance_list: # Yes; see if we can claim the nearest one: nearest_possible_entity = entity_distance_dict[distance] if nearest_possible_entity in this_frame_entity_list: continue # Found the nearest entity to claim: entity_found = True nearest_possible_entity[ 2] = frame_t0 # Update last_time_seen nearest_possible_entity[ 3] = target # Update the new location this_frame_entity_list.append(nearest_possible_entity) break if entity_found == False: # It's a new entity. color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) name = hashlib.md5(str(frame_t0) + str(color)).hexdigest()[:6] last_time_seen = frame_t0 new_entity = [name, color, last_time_seen, target] this_frame_entity_list.append(new_entity) # Now "delete" any not-found entities which have expired: entity_ttl = 1.0 # 1 sec. ent_count = 0 for entity in last_frame_entity_list: last_time_seen = entity[2] if frame_t0 - last_time_seen > entity_ttl: pass else: # Save it for next time... not expired yet: this_frame_entity_list.append(entity) ent_count += 1 # For next frame: last_frame_entity_list = this_frame_entity_list # Draw the found entities to screen: count = 0 if ent_count != 0: entity = this_frame_entity_list[0] center_point = entity[3] c = entity[1] # RGB color tuple # print '%s %d %d %d' % (entity[0], count, center_point[0], center_point[1]) cv.Circle(display_image, center_point, 20, cv.CV_RGB(c[0], c[1], c[2]), 1) cv.Circle(display_image, center_point, 15, cv.CV_RGB(c[0], c[1], c[2]), 1) cv.Circle(display_image, center_point, 10, cv.CV_RGB(c[0], c[1], c[2]), 2) cv.Circle(display_image, center_point, 5, cv.CV_RGB(c[0], c[1], c[2]), 3) text_font = cv.InitFont(cv.CV_FONT_HERSHEY_COMPLEX, .5, .5, 0.0, 1, cv.CV_AA) text_coord = (5, 15) text_color = cv.CV_RGB(255, 255, 255) x = 50 + (center_point[0] * 80 / 320) y = 20 + (center_point[1] * 80 / 240) if self.have_eye: self.ServoMove(0, int(x)) self.ServoMove(1, int(y)) s = '%3.0d %3.0d' % (x, y) cv.PutText(display_image, str(s), text_coord, text_font, text_color) #print "min_size is: " + str(min_size) # Listen for ESC or ENTER key c = cv.WaitKey(7) % 0x100 if c == 27 or c == 10: break # Toggle which image to show if chr(c) == 'd': image_index = (image_index + 1) % len(image_list) image_name = image_list[image_index] # Display frame to user if image_name == "display": image = display_image # cv.PutText( image, "AABBs and contours", text_coord, text_font, text_color ) elif image_name == "camera": image = camera_image cv.PutText(image, "No overlay", text_coord, text_font, text_color) elif image_name == "difference": image = difference cv.PutText(image, "Difference Image", text_coord, text_font, text_color) elif image_name == "faces": # Do face detection detect_faces(camera_image, haar_cascade, mem_storage) image = camera_image # Re-use camera image here cv.PutText(image, "Face Detection", text_coord, text_font, text_color) elif image_name == "threshold": # Convert the image to color. cv.CvtColor(grey_image, display_image, cv.CV_GRAY2RGB) image = display_image # Re-use display image here cv.PutText(image, "Motion Mask", text_coord, text_font, text_color) cv.ShowImage("Target", image) if self.writer: cv.WriteFrame(self.writer, image) frame_t1 = time.time() t1 = time.time() time_delta = t1 - t0 processed_fps = float(frame_count) / time_delta print "Got %d frames. %.1f s. %f fps." % (frame_count, time_delta, processed_fps)
boundingRect = cv.BoundingRect(list(contour)) p1 = (boundingRect[0], boundingRect[1]) p2 = (boundingRect[0] + boundingRect[2], boundingRect[1] + boundingRect[3]) boundingBoxList.append((p1, p2)) polygonPoints = cv.ApproxPoly(list(contour), memStorage, cv.CV_POLY_APPROX_DP) #Show the contours cv.FillPoly(greyImage, [ list(polygonPoints), ], cv.CV_RGB(255, 255, 255), 0, 0) cv.PolyLine(displayImage, [ polygonPoints, ], 0, cv.CV_RGB(255, 255, 255), 1, 0, 0) contour = contour.h_next() # Find the average size of the bounding box targets and remove ones that are 5% or less than the average as noise boxAreas = [] for box in boundingBoxList: boxWidth = box[right][0] - box[left][0] boxHeight = box[bottom][0] - box[top][0] boxAreas.append(boxWidth * boxHeight) averageBoxArea = 0.0 if len(boxAreas): averageBoxArea = float(sum(boxAreas) / len(boxAreas))
def find_biggest_region(pub): """ finds all the contours in threshed image, finds the largest of those, and then marks in in the main image """ # get D so that we can change values in it global D # Create a copy image of thresholds then find contours on that image cv.Copy(D.threshed_image, D.copy) # copy threshed image # this is OpenCV's call to find all of the contours: contours = cv.FindContours(D.copy, D.storage, cv.CV_RETR_EXTERNAL, cv.CV_CHAIN_APPROX_SIMPLE) # Next we want to find the *largest* contour # this is the standard algorithm: # walk the list of all contours, remembering the biggest so far: if len(contours) > 0: biggest = contours biggestArea = cv.ContourArea(contours) while contours != None: nextArea = cv.ContourArea(contours) if biggestArea < nextArea: biggest = contours biggestArea = nextArea contours = contours.h_next() # Use OpenCV to get a bounding rectangle for the largest contour br = cv.BoundingRect(biggest, update=0) # Draw a red box from (42,42) to (84,126), for now (you'll change this): x = br[0] y = br[1] w = br[2] h = br[3] upper_left = (x, y) lower_left = (x, y + h) lower_right = (x + w, y + h) upper_right = (x + w, y) cv.PolyLine(D.image, [[upper_left, lower_left, lower_right, upper_right]], 1, cv.RGB(255, 0, 0)) # Draw the circle, at the image center for now (you'll change this) center = ((2 * x + w) / 2, (2 * y + h) / 2) cv.Circle(D.image, center, 10, cv.RGB(255, 255, 0), thickness=2, lineType=8, shift=0) # Draw matching contours in white with inner ones in green cv.DrawContours(D.image, biggest, cv.RGB(255, 255, 255), cv.RGB(0, 255, 0), 1, thickness=2, lineType=8, offset=(0, 0)) # publish the rectangle vertex coordinates pub.publish(','.join(map(str, [upper_left, lower_right])))
def displayRobot(self, (x_mm, y_mm, theta_deg), color=ROBOT_COLOR_BGR, scale=1, line_thickness=1): # Get a polyline (e.g. triangle) to represent the robot icon robot_points = self.robot_polyline(scale) # Rotate the polyline by the current angle robot_points = map(lambda pt: rotate(pt, theta_deg), robot_points) # Convert the robot position from meters to pixels x_pix, y_pix = self.mm2pix(x_mm), self.mm2pix(y_mm) # Move the polyline to the current robot position robot_points = map(lambda pt: (x_pix+pt[0], y_pix+pt[1]), robot_points) # Add an icon for the robot cv.PolyLine(self.image, [robot_points], True, color, line_thickness) def displayScan(self, scan, offset_mm = (0,0), color=SCANPOINT_COLOR_BGR): for point in scan: cv.Circle(self.image, (self.mm2pix(point[0]+offset_mm[0]), self.mm2pix(point[1]+offset_mm[1])), \ SCANPOINT_RADIUS, color) def displayVelocities(self, dxy_mm, dtheta_deg): # Add velocity bars self.show_velocity(dxy_mm, SENSOR_V_MAX_MM, ' dXY', SENSOR_V_Y) self.show_velocity(dtheta_deg, SENSOR_THETA_MAX_DEG, 'dTheta', SENSOR_THETA_Y) def displayTrajectory(self, trajectory):