def segmentize(self, input_img): histogram = self.__calculate_histogram(input_img) (peaks, bottoms) = find_peaks(histogram, max(histogram) / 8) for peak in peaks: if between(peak, self.expectations['table']): self.ranges['table'] = find_hill(histogram, peak, 0.01) break #stop searching, we want the first peak since that is the highest large object. if not 'table' in self.ranges: if self.verbose: cv.ShowImage("histogram", self.__render_histogram(histogram)) return None self.ranges['objects'] = (1, self.ranges['table'][0] - 1) print self.ranges if self.verbose: cv.ShowImage("histogram", self.__render_histogram(histogram)) objects_img = create_empty_image((input_img.width, input_img.height)) cv.SetImageROI(objects_img, cv.GetImageROI(input_img)) cv.InRangeS(input_img, cv.Scalar(self.ranges['objects'][0]), cv.Scalar(self.ranges['objects'][1]), objects_img) table_img = create_empty_image((input_img.width, input_img.height)) cv.SetImageROI(table_img, cv.GetImageROI(input_img)) cv.InRangeS(input_img, cv.Scalar(self.ranges['table'][0]), cv.Scalar(self.ranges['table'][1]), table_img) return {'objects': objects_img, 'table': table_img}
def __draw_verbose(self, bin_img, points): seg_img = clone_color_image(bin_img) if len(points): # an extrapolated line! (a, b) = polyfit([p.x if p.x > 0 else 1 for p in points], [p.y for p in points], 1) f = lambda x: a * x + b (dx, dy, width, height) = cv.GetImageROI(seg_img) # draw the line (by drawing points, how inefficient!) for x in range(width): y = f(x) cv.Circle(seg_img, (int(dx + x), int(dy + y)), 2, (0, 0, 255, 0), 2, cv.CV_AA) # calculate the color of the points for idx, point in enumerate(points): if idx == 0 or idx == len(points) - 1: setattr(point, "colour", (255, 255, 255, 0)) else: setattr(point, "colour", (point.distance(points[idx - 1]) * 2, 255, point.distance(points[idx + 1]) * 2, 0)) # draw the individual pionts for point in points: cv.Circle(seg_img, point.move((dx, dy)).as_cv_point(), 3, point.colour, 2, cv.CV_AA) cv.ShowImage("TableDetector", seg_img) cv.WaitKey(10)
def detect(self, img): (dx, dy, width, height) = cv.GetImageROI(img) # generate a set of points points = [Point(x, height - 1) for x in range(0, width - 1, 5)] # move points as far up as possible self.__drop_points(points, img) points = self.__remove_unmoved_points(points, height - 1) # remove points that got stuck in noise points = self.__remove_outliers(points, self.outlier_threshold) if self.verbose: self.__draw_verbose(img, points) # if there are no points left (like, shitty image or no table) # return nothing if len(points) == 0: return None table = self.__extract_table(points, (width, height)) if self.verbose: print table return table
def estimate_ballot_rot(I, Imarkfull, bbs, MAX_THETA=2.0, K=5): roi_prev = cv.GetImageROI(I) w_markfull, h_markfull = cv.GetSize(Imarkfull) theta_tm = None for bb in bbs: roi_cur = tuple( map(lambda x: int(round(x)), (roi_prev[0] + bb[0], roi_prev[1] + bb[1], bb[2] - bb[0], bb[3] - bb[1]))) cv.SetImageROI(I, roi_cur) w_cur, h_cur = cv.GetSize(I) if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Imiddle.png' <><><><>") cv.SaveImage("_Imiddle.png", I) pdb.set_trace() matches = tempmatch.get_tempmatches( Imarkfull, [I], T=0.9, do_smooth=tempmatch.SMOOTH_BOTH_BRD, xwinI=5, ywinI=5, xwinA=5, ywinA=5)[0] matches = sorted(matches, key=lambda t: t[0]) if matches: xs = np.array([t[0] for t in matches]) ys = np.array([cv.GetSize(I)[1] - t[1] for t in matches]) if len(xs) <= 1: print_dbg("==== Couldn't find enough marks in '_Imiddle.png'.") continue # Filter out any obvious outliers lonely_idxs = detect_lonely_vals(ys, h_markfull) xs = np.delete(xs, lonely_idxs) ys = np.delete(ys, lonely_idxs) if len(xs) <= 1: print_dbg("==== Couldn't find enough marks in '_Imiddle.png'.") continue # Discovered marks must take up at least K*w_markfull space. x_area = max(xs) - min(xs) if x_area < (K * w_markfull): print_dbg( "==== Marks only took up {0}, too small space.".format( x_area)) else: theta_tm_ = estimate_rotation(xs, ys) if abs(theta_tm_) > MAX_THETA: print_dbg( "==== Theta was too large: {0}".format(theta_tm_)) else: theta_tm = theta_tm_ break else: print_dbg("==== Couldn't find any marks in '_Imiddle.png'.") cv.SetImageROI(I, roi_prev) return theta_tm
def drawit(I, bbs, imgpath, isflip=False): Icolor = cv.LoadImage(imgpath, cv.CV_LOAD_IMAGE_COLOR) if isflip: cv.Flip(Icolor, Icolor, -1) cv.SetImageROI(Icolor, cv.GetImageROI(I)) for (x1, y1, x2, y2) in bbs: cv.Rectangle(Icolor, (x1, y1), (x2, y2), cv.CV_RGB(255, 0, 0)) print "<><><><> Saving '_Icolor.png' <><><><>" cv.SaveImage("_Icolor.png", Icolor) pdb.set_trace()
def segmentize(self, img): '''Extract the depth level that only contains the table, ignoring the objects and arms (i.e. as if they are holes in the table)''' layers = {} for name, (low, high) in self.ranges.iteritems(): layer = cv.CreateImage((img.width, img.height), cv.IPL_DEPTH_8U, 1) cv.SetImageROI(layer, cv.GetImageROI(img)) cv.InRangeS(img, low, high, layer) layers[name] = layer return layers
def __drop_points(self, points, seg_img): (dx, dy, width, height) = cv.GetImageROI(seg_img) for point in points: for y in range(point.y - 1, 0, -1): channel = cv.Get2D(seg_img, dy + y, dx + point.x) #prev_channel = cv.Get2D(seg_img, dy + y + 1, dx + point.x) #diff = channel[0] - prev_channel[0] #if diff > 1: #seg_img is binary, so values should be 0 or 255 if channel[0] > 128: break point.y = y
def is_backside(decodings, mark_locs, I, Izero): """ Applies Sequoia-specific knowledge. A backside ballot side has the following 'barcode' values (assume right-side-up): UpperLeft: "0" UpperRight: "" (Just a black bar) LowerLeft: "0" LowerRight: "0" Note: This doesn't detect empty backsides. Assumes that the decoder is 'good enough' such that it will not spuriously return "" or "0" for an real front-side barcode. Output: bool isBack, bool isFlip """ if decodings[0] == "0" and decodings[1] == "": # Possibly up-right backside. return True, False elif decodings[0] == "0" and decodings[1] == "0": return True, True # Try to handle if ballot is partially-cutoff. _roi = cv.GetImageROI(I) cv.ResetImageROI(I) w_img, h_img = cv.GetSize(I) w_fact, h_fact = 0.19, 0.13 w_patch, h_patch = int(round(w_img * w_fact)), int(round(h_img * h_fact)) if decodings[0] == "": # LHS is possibly cut-off cv.SetImageROI(I, (w_img - w_patch, h_img - h_patch, w_patch, h_patch)) x1, y1, score = tempmatch.bestmatch( Izero, [I], do_smooth=tempmatch.SMOOTH_IMG_BRD)[0] cv.SetImageROI(I, _roi) if score >= 0.9: return True, True if decodings[1] == "" else False else: # No idea! What? Definitely a strange case... print "...Wow, this is unexpected!" return False, None elif decodings[1] == "" and decodings[0] == "0": # RHS is possibly cut-off cv.SetImageROI(I, (0, h_img - h_patch, w_patch, h_patch)) x1, y1, score = tempmatch.bestmatch( Izero, [I], do_smooth=tempmatch.SMOOTH_IMG_BRD)[0] cv.SetImageROI(I, _roi) if score >= 0.9: return True, False else: return True, True return False, None
def mean(img, x, y, size=10): oldRoi = cv.GetImageROI(img) #make sure roi is within image bounds x = min(x, img.width - 1) x = max(x, 0) y = min(y, img.height - 1) y = max(y, 0) cv.SetImageROI(img, (x - size / 2, y - size / 2, size, size)) avg = cv.Avg(img) cv.SetImageROI(img, oldRoi) return (avg[0] + avg[1] + avg[2]) / 3.0
def draw(self, img): ''' Draw this corner on img @param img: ''' rect = cv.GetImageROI(img) cv.ResetImageROI(img) col = (255, 255, 255) cv.Line(img, self.prev, self.p, col) cv.Line(img, self.p, self.next, col) # cv.Line(img, self.p, add(self.p, rotateVec((30, 0), self.rotation), 1), col) cv.Circle(img, self.p, 2, col) font = cv.InitFont(cv.CV_FONT_HERSHEY_COMPLEX_SMALL, 0.7, 0.7) cv.PutText(img, "(%d,%d)" % self.p, self.p, font, col) cv.SetImageROI(img, rect)
def find_corners(self): ''' Tries to find corners or to predict them. Return empty list, if every corner is found, or list of points in the area which tell where to do futher checking ''' time = self.m_d.time if time - self.last_seen >= MAX_SEEN: return False #cv.ResetImageROI(draw_img) ncorners = [] bounds = [] for c in self.corners: db.db_break("find_corners") cands = c.get_candidates(self.m_d) min = NOT_SIMILLAR bestcand = None for cand in cands: if cand.similarity < min: min = cand.similarity bestcand = cand ncorners.append(bestcand) bounds.extend(cvrect(cv.GetImageROI(self.m_d.bw_img))) if bestcand is None: pass db.pr([ncorners], "find_corners") for cor in ncorners: if cor is not None: cor.draw(self.m_d.tmp_img) if None in ncorners: pass CP = CornerPredictor(self.corners, time, self.m_d) ncorners = CP.predict_corners(ncorners) db.pr([ncorners], "new corners") if ncorners is not None: points = [x.p for x in ncorners] correctness = self.code_correctness(points) if correctness > REQUIRED_CORRECTNESS: self.set_new_position(ncorners) return True else: db.PolyLine(self.m_d.tmp_img, [points], True, (255, 255, 255), "%.2f" % correctness) self.m_d.borders.extend(CP.bounds) return False
def find_col_x1(I, Icol, bb, K=3, AX=0.2, AY=0.2, T=0.9): """ Tries to find the column of marks on I, using ICOL as a ref. image in template matching. """ roi_prev = cv.GetImageROI(I) shift_roi(I, bb[0], bb[1], bb[2] - bb[0], bb[3] - bb[1]) w_A, h_A = cv.GetSize(Icol) w_I, h_I = cv.GetSize(I) M = cv.CreateMat(h_I - h_A + 1, w_I - w_A + 1, cv.CV_32F) cv.MatchTemplate(I, Icol, M, cv.CV_TM_CCOEFF_NORMED) if DEBUG_SAVEIMGS: M_np = np.array(M) import scipy.misc print_dbg("<><><><> Saving '_Mbase.png' <><><><>") cv.SaveImage("_Mbase.png", I) print_dbg("<><><><> Saving '_M.png' <><><><>") scipy.misc.imsave("_M.png", M) pdb.set_trace() cv.SetImageROI(I, roi_prev) i = 0 xs = [] _xamt, _yamt = int(round(AX * w_A)), int(round(AY * h_A)) while i < K: minResp, maxResp, minLoc, maxLoc = cv.MinMaxLoc(M) if maxResp < T: break x, y = maxLoc # Find the /leftmost/ match: don't find a match in the middle # of a column. while M[y, x] >= T: x -= 1 xs.append((x + bb[0])) _x1 = max(1, x - _xamt) _x2 = max(1, x + _xamt) _y1 = max(1, y - _yamt) _y2 = max(1, y + _yamt) M[_y1:_y2, _x1:_x2] = -1.0 i += 1 if not xs: return None elif len(xs) == 1: return xs[0] return np.median(xs)
def set_new_position(self, points_or_corners, offset=True, scale=1): ''' Sets new position for this marker using points (in order) @param points_or_corners: list of points or corners @param offset: if true, image ROI is checked and points are shifted ''' if len(points_or_corners) > 0 and type(points_or_corners[0]) == tuple: self.predicted = -1 points = points_or_corners img = self.m_d.img (x, y, _, _) = rect = cv.GetImageROI(img) if offset and (x, y) <> (0, 0): points = map(lambda z: add((x, y), z), points) cv.ResetImageROI(img) crit = (cv.CV_TERMCRIT_EPS + cv.CV_TERMCRIT_ITER, 30, 0.1) if (scale > 1): points = cv.FindCornerSubPix(self.m_d.gray_img, points, (scale * 2 + 4, scale * 2 + 4), (-1, -1), crit) else: points = cv.FindCornerSubPix(self.m_d.gray_img, points, (3, 3), (-1, -1), crit) ncorners = Corner.get_corners(points, self.m_d.time) if len(self.corners) <> 0: for i, cor in enumerate(ncorners): cor.compute_change(self.corners[i]) cv.SetImageROI(img, rect) else: ncorners = points_or_corners self.predicted += len(filter(lambda x: x.is_predicted, ncorners)) for i, c in enumerate(ncorners): c.black_inside = self.black_inside # if len(self.corners)==4: # if dist_points(c.p, self.corners[i].p)<4: # c.p=self.corners[i].p self.corners = ncorners self.area = abs(cv.ContourArea(self.points)) self.last_seen = self.m_d.time self.model_view = None
def process_frame(self, frame): # Resize image to 320x240 #copy = cv.CreateImage(cv.GetSize(frame), 8, 3) #cv.Copy(frame, copy) #cv.SetImageROI(frame, (0, 0, 320, 240)) #cv.Resize(copy, frame, cv.CV_INTER_NN) found_hedge = False cv.Smooth(frame, frame, cv.CV_MEDIAN, 7, 7) # Set binary image to have value channel hsv = cv.CreateImage(cv.GetSize(frame), 8, 3) binary = cv.CreateImage(cv.GetSize(frame), 8, 1) cv.CvtColor(frame, hsv, cv.CV_BGR2HSV) cv.SetImageCOI(hsv, 1) cv.Copy(hsv, binary) cv.SetImageCOI(hsv, 0) cv.AdaptiveThreshold( binary, binary, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY_INV, self.adaptive_thresh_blocksize, self.adaptive_thresh, ) # Morphology ''' kernel = cv.CreateStructuringElementEx(3, 3, 1, 1, cv.CV_SHAPE_ELLIPSE) cv.Erode(binary, binary, kernel, 1) cv.Dilate(binary, binary, kernel, 1) ''' if self.debug: color_filtered = cv.CloneImage(binary) # Get Edges #cv.Canny(binary, binary, 30, 40) # Hough Transform line_storage = cv.CreateMemStorage() raw_lines = cv.HoughLines2(binary, line_storage, cv.CV_HOUGH_STANDARD, rho=1, theta=math.pi / 180, threshold=self.hough_threshold, param1=0, param2=0) # Get vertical lines vertical_lines = [] for line in raw_lines: if line[1] < self.vertical_threshold or \ line[1] > math.pi - self.vertical_threshold: vertical_lines.append((abs(line[0]), line[1])) # Group vertical lines vertical_line_groups = [ ] # A list of line groups which are each a line list for line in vertical_lines: group_found = False for line_group in vertical_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groups.append([line]) # Average line groups into lines vertical_lines = [] for line_group in vertical_line_groups: rhos = map(lambda line: line[0], line_group) angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_lines.append(line) # Get horizontal lines horizontal_lines = [] for line in raw_lines: dist_from_horizontal = (math.pi / 2 + line[1]) % math.pi if dist_from_horizontal < self.horizontal_threshold or \ dist_from_horizontal > math.pi - self.horizontal_threshold: horizontal_lines.append((abs(line[0]), line[1])) # Group horizontal lines horizontal_line_groups = [ ] # A list of line groups which are each a line list for line in horizontal_lines: group_found = False for line_group in horizontal_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: horizontal_line_groups.append([line]) if len(horizontal_line_groups) is 1: self.seen_crossbar = True rhos = map(lambda line: line[0], horizontal_line_groups[0]) angles = map(lambda line: line[1], horizontal_line_groups[0]) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) horizontal_lines = [line] else: self.seen_crossbar = False horizontal_lines = [] self.left_pole = None self.right_pole = None if len(vertical_lines) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 # TODO: If one pole is seen, is it left or right pole? # Calculate planar distance r (assuming we are moving perpendicular to # the hedge) if self.left_pole and self.right_pole: theta = abs(self.left_pole - self.right_pole) self.r = 3 / tan(radians(theta / 2)) else: self.r = None if self.r and self.seen_crossbar: bar_phi = (-1 * horizontal_lines[0][0] + frame.height / 2) / (frame.height / 2) * 32 self.crossbar_depth = self.r * atan(radians(bar_phi)) else: self.crossbar_depth = None if self.debug: cv.CvtColor(color_filtered, frame, cv.CV_GRAY2RGB) libvision.misc.draw_lines(frame, vertical_lines) libvision.misc.draw_lines(frame, horizontal_lines) #cv.ShowImage("Hedge", cv.CloneImage(frame)) svr.debug("Hedge", cv.CloneImage(frame)) # populate self.output with infos self.output.seen_crossbar = self.seen_crossbar self.output.left_pole = self.left_pole self.output.right_pole = self.right_pole self.output.r = self.r self.output.crossbar_depth = self.crossbar_depth self.return_output() print self
def process_frame(self, frame): ################ #setup CV ###### ################ print "processing frame" (w, h) = cv.GetSize(frame) #generate hue selection frames ones = np.ones((h, w, 1), dtype='uint8') a = ones * (180 - self.target_hue) b = ones * (180 - self.target_hue + 20) a_array = cv.fromarray(a) b_array = cv.fromarray(b) #create locations for the test frame and binary frame frametest = cv.CreateImage(cv.GetSize(frame), 8, 3) binarytest = cv.CreateImage(cv.GetSize(frame), 8, 1) #use the red channel for the binary frame (just for debugging purposes) cv.Copy(frame, frametest) cv.SetImageCOI(frametest, 3) cv.Copy(frametest, binarytest) #reset the COI for test frame to RGB. cv.SetImageCOI(frametest, 0) # Resize image to 320x240 #copy = cv.CreateImage(cv.GetSize(frame), 8, 3) #cv.Copy(frame, copy) #cv.SetImageROI(frame, (0, 0, 320, 240)) #cv.Resize(copy, frame, cv.CV_INTER_NN) found_gate = False #create a new frame for comparison purposes unchanged_frame = cv.CreateImage(cv.GetSize(frame), 8, 3) cv.Copy(frame, unchanged_frame) #apply noise filter #1 cv.Smooth(frame, frame, cv.CV_MEDIAN, 7, 7) # Set binary image to have saturation channel hsv = cv.CreateImage(cv.GetSize(frame), 8, 3) binary = cv.CreateImage(cv.GetSize(frame), 8, 1) cv.CvtColor(frame, hsv, cv.CV_BGR2HSV) cv.SetImageCOI(hsv, 1) cv.Copy(hsv, binary) #spin the color wheel (psuedo-code for later if necessary) # truncate spectrum marked as end # shift all values up based on truncating value (mask out 0 regions) # take truncated bits, and flip them (180->0, 179->1...) # dnow that truncated bits are flipped, add them back in to final image #Reset hsv COI cv.SetImageCOI(hsv, 0) #correct for wraparound on red spectrum cv.InRange(binary, a_array, b_array, binarytest) #generate mask cv.Add(binary, cv.fromarray(ones * 180), binary, mask=binarytest) #use mask to selectively add values #run adaptive threshold for edge detection cv.AdaptiveThreshold( binary, binary, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY_INV, self.adaptive_thresh_blocksize, self.adaptive_thresh, ) # Morphology kernel = cv.CreateStructuringElementEx(5, 5, 3, 3, cv.CV_SHAPE_ELLIPSE) cv.Erode(binary, binary, kernel, 1) cv.Dilate(binary, binary, kernel, 1) if self.debug: color_filtered = cv.CloneImage(binary) # Get Edges cv.Canny(binary, binary, 30, 40) # Hough Transform line_storage = cv.CreateMemStorage() raw_lines = cv.HoughLines2(binary, line_storage, cv.CV_HOUGH_STANDARD, rho=1, theta=math.pi / 180, threshold=self.hough_threshold, param1=0, param2=0) # Get vertical lines vertical_lines = [] i = 0 for line in raw_lines: if line[1] < self.vertical_threshold or \ line[1] > (math.pi-self.vertical_threshold): #absolute value does better grouping currently vertical_lines.append((abs(line[0]), line[1])) i += 1 # print message to user for performance purposes logging.debug("{} possibilities reduced to {} lines".format( i, len(vertical_lines))) # Group vertical lines vertical_line_groups = [ ] #A list of line groups which are each a line list i = 0 for line in vertical_lines: group_found = False for line_group in vertical_line_groups: i += 1 if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groups.append([line]) #quick debugging statement logging.debug("{} internal iterations for {} groups".format( i, len(vertical_line_groups))) # Average line groups into lines vertical_lines = [] for line_group in vertical_line_groups: rhos = map(lambda line: line[0], line_group) #get rho of each line angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_lines.append(line) self.left_pole = None self.right_pole = None self.returning = 0 self.found = False if len(vertical_lines) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.returning = (self.left_pole + self.right_pole) / 2 logging.info("Returning {}".format(self.returning)) #If this is first iteration, count this as seeing the gate if self.last_seen < 0: self.last_center = None self.last_seen = 0 #increment a counter if result is good. if self.last_center is None: self.last_center = self.returning self.seen_count = 1 elif math.fabs(self.last_center - self.returning) < self.center_trans_thresh: self.seen_count += 1 self.last_seen += 2 else: self.last_seen -= 1 #if not convinced, forget left/right pole. Else, proclaim success. if self.seen_count < self.seen_count_thresh: self.left_pole = None self.right_pole = None else: print "FOUND CENTER AND RETURNED IT" self.found = True else: self.returning = 0 if self.last_seen < 0: self.last_center = None self.last_seen = 0 self.last_seen -= 1 self.left_pole = None self.right_POLE = None #extra debugging stuff if self.debug: cv.CvtColor(color_filtered, frame, cv.CV_GRAY2RGB) libvision.misc.draw_lines(frame, vertical_lines) if self.found: cv.Circle(frame, (int(frame.width / 2 + self.returning), int(frame.height / 2)), 15, (0, 255, 0), 2, 8, 0) font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1, 1, 1, 3) cv.PutText(frame, "Gate Sent to Mission Control", (100, 400), font, (255, 255, 0)) #print frame.width #cv.ShowImage("Gate", cv.CloneImage(frame)) svr.debug("Gate", cv.CloneImage(frame)) svr.debug("Unchanged", cv.CloneImage(unchanged_frame)) self.return_output()
def shift_roi(I, x, y, w, h): roi_prev = cv.GetImageROI(I) new_roi = tuple(map(int, (roi_prev[0] + x, roi_prev[1] + y, w, h))) cv.SetImageROI(I, new_roi) return I
def decode_i2of5(img, n, topbot_pairs, orient=VERTICAL, debug=False, imgP=None, cols=4): """ Decodes the interleaved two-of-five barcode. Returns a string. Input: IplImage img: int n: Number of digits in the barcode. list TOPBOT_PAIRS: [[IplImage topguard, IplImage botguard], ...]. int COLS: Splits the barcode into COLS columns, separately runs the decoding on each column, then chooses the most popular decoding result. Output: (str decoded, tuple bb), where BB is the bounding box of the barcode within IMG: (x, y, w, h) """ # For now, assume that the barcode is bottom-to-top. TOP_GUARD, BOT_GUARD = topbot_pairs[0] TOP_GUARD = smooth_constborder(TOP_GUARD, xwin=3, ywin=3, val=255) BOT_GUARD = smooth_constborder(BOT_GUARD, xwin=3, ywin=3, val=255) TOP_WHITE_PAD = 24 # Num. pixs from white->top guard barcode BOT_WHITE_PAD = 31 # 1.) Find location of top/bottom guards, to find location of barcode bc_height = BC_14_HEIGHT if n == 14 else BC_12_HEIGHT bc_loc = find_barcode_loc_tm(img, bc_height, TOP_GUARD, BOT_GUARD, TOP_WHITE_PAD, BOT_WHITE_PAD, imgP=imgP) if bc_loc == None: if len(topbot_pairs) == 1: return None, [0, 0, 1, 1], None return decode_i2of5(img, n, topbot_pairs[1:], imgP=imgP, cols=cols, debug=debug) # 2.) Crop the barcode. #cv.SaveImage("_imgcrop_pre.png", img) roi_precrop = cv.GetImageROI(img) cv.SetImageROI(img, shiftROI(cv.GetImageROI(img), bc_loc)) #cv.SaveImage("_imgcrop.png", img) decodings = [] w_bc, h_bc = cv.GetSize(img) bc_roi = cv.GetImageROI(img) for curcol in xrange(cols): width = int(round(w_bc / cols)) x1 = width * curcol cv.SetImageROI(img, shiftROI(bc_roi, (x1, 0, width, h_bc))) decodings.append( decode_barcode(img, n, bc_loc[:], xoff=x1, imgP=imgP, debug=debug)) dstr_out, bbloc_out, bbstripes_out = get_most_popular(decodings, w_bc) cv.SetImageROI(img, roi_precrop) if dstr_out == None: if len(topbot_pairs) == 1: # We tried our best, give up. return dstr_out, bbloc_out, bbstripes_out else: return decode_i2of5(img, n, topbot_pairs[1:], imgP=imgP, cols=cols, debug=debug) return dstr_out, bbloc_out, bbstripes_out
def decoder_v2_helper(I, Icol, bbs_rough, w_markfull, h_markfull, isflip, H_GAP, theta, i1_blk, i2_blk, j1_blk, j2_blk, imgpath=None, find_col=True, W_MARK=WIDTH_MARK, H_MARK=HEIGHT_MARK, idx2tol=None): result = None roi_prev = cv.GetImageROI(I) w, h = cv.GetSize(I) if find_col: w, h = cv.GetSize(I) bb_left = (0.0, 0.86 * h, 0.06 * w, h - 1) bb_right = ((w - 1) - (0.06 * w), 0.86 * h, w - 1, h - 1) if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Inocolflush.png' <><><><>") cv.SaveImage("_Inocolflush.png", I) x1_left = find_col_x1(I, Icol, bb_left) x1_right = find_col_x1(I, Icol, bb_right) print_dbg("== x1_left={0} x1_right={1}".format(x1_left, x1_right)) x1_left = x1_left if x1_left != None else 0 x1_right = (min(h - 1, x1_right + w_markfull) if x1_right != None else w - 1) else: x1_left, x1_right = 0, w - 1 bb_thecols = (x1_left, 0, x1_right, h - 1) shift_roi(I, bb_thecols[0], bb_thecols[1], bb_thecols[2] - bb_thecols[0], bb_thecols[3] - bb_thecols[1]) roi_flushcol = cv.GetImageROI(I) if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Iflushcols.png' <><><><>") cv.SaveImage("_Iflushcols.png", I) pdb.set_trace() for bb_rough in bbs_rough: cv.SetImageROI(I, roi_flushcol) shift_roi(I, bb_rough[0], bb_rough[1], bb_rough[2] - bb_rough[0], bb_rough[3] - bb_rough[1]) w_foo, h_foo = cv.GetSize(I) Icor, H = rotate_img(I, -theta) Hfoo = np.eye(3) Hfoo[0:2, 0:3] = np.array(H) H_inv = np.linalg.inv(Hfoo) H_inv = H_inv[0:2] if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Icor.png' <><><><>") cv.SaveImage("_Icor.png", Icor) i1_blk_cor, i2_blk_cor, j1_blk_cor, j2_blk_cor = compute_border( iplimage2np(Icor)) shift_roi(Icor, j1_blk_cor, i1_blk_cor, cv.GetSize(Icor)[0] - (j1_blk_cor + j2_blk_cor), cv.GetSize(Icor)[1] - (i1_blk_cor + i2_blk_cor)) if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Icor_noblkborder.png' <><><><>") cv.SaveImage("_Icor_noblkborder.png", Icor) def to_orig_coords(bb, H_inv): """ Returns BB (in corrected coord. system) to the original coordinate system. """ x1, y1 = transform_pt((bb[0], bb[1]), H_inv, (w_foo, h_foo)) x1 += bb_rough[0] + bb_thecols[0] y1 += bb_rough[1] x2, y2 = transform_pt((bb[2], bb[3]), H_inv, (w_foo, h_foo)) x2 += bb_rough[0] + bb_thecols[0] y2 += bb_rough[1] return tuple(map(lambda x: int(round(x)), (x1, y1, x2, y2))) w_cor, h_cor = cv.GetSize(Icor) candidates = [] y1_step = int(h_markfull / 4.0) def tighten_bbs(bbs, decoding, I): """ Given initial boundingboxes around each mark, compute new bbs such that each 'on' mark is at the upper-left corner. """ def find_black(I, x, BLACK=130, y1_start=0): """ Find y1 of first black pixel, starting from (X, 0). """ w, h = cv.GetSize(I) for y1 in xrange(y1_start, h): if I[y1, x] <= BLACK: return y1 return None w_img, h_img = cv.GetSize(I) bbs_out = [] y1s_ons = [] if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Itightenbbs.png' <><><><>") cv.SaveImage("_Itightenbbs.png", I) # First, estimate the y1's for the left/right col marks, # since they're the 'easiest' to find y1s_leftright = [] for (x1, y1, x2, y2) in (bbs[0], bbs[-1]): w_rect, h_rect = (x2 - x1), (y2 - y1) x1s = (x1 + int(w_rect * 0.15), x1 + int(w_rect / 4.0), x1 + int(w_rect / 2.0), x1 + int( (3 * w_rect) / 4.0), (x2 - 1) - int(w_rect * 0.1)) x1s = [x for x in x1s if x < w_img] y1s = [find_black(I, x1_cur, y1_start=0) for x1_cur in x1s] y1s = [_y1 for _y1 in y1s if _y1 != None] if not y1s: y1_out = 0 # Default to sensible value else: y1_out = int(round(np.median(y1s))) y1s_leftright.append(y1_out) for i, (x1, y1, x2, y2) in enumerate(bbs): val = decoding[i] if val == '0': bbs_out.append((x1, y1, x2, y2)) continue w_rect, h_rect = (x2 - x1), (y2 - y1) x1s = (x1 + int(w_rect * 0.15), x1 + int(w_rect / 4.0), x1 + int(w_rect / 2.0), x1 + int( (3 * w_rect) / 4.0), (x2 - 1) - int(w_rect * 0.1)) x1s = [x for x in x1s if x < w_img] if i == 0 or i == len(bbs) - 1: _y1 = 0 else: _y1 = max(int(round(y1 - (h_markfull / 4.0))), 0) y1s = [find_black(I, x1_cur, y1_start=_y1) for x1_cur in x1s] y1s = [_y1 for _y1 in y1s if _y1 != None] # Filter out the bad results #y1_out = int(round((np.mean(y1s)+np.median(y1s))/2.0)) if not y1s: y1_out = 0 # Default to sensible value else: y1_out = int(round(np.median(y1s))) y2_out = y1_out + (y2 - y1) - 1 y1s_ons.append(y1_out) bbs_out.append((x1, y1_out - 1, x2, y2_out - 1)) # Finally, clamp all y1s of '0' marks to some fixed y1 y1_clamp = int(round(np.mean(y1s_ons))) bbs_out_final = [] for i, (x1, y1, x2, y2) in enumerate(bbs_out): if decoding[i] == '0': bbs_out_final.append( (x1, y1_clamp, x2, y1_clamp + (y2 - y1) - 1)) else: bbs_out_final.append((x1, y1, x2, y2)) return bbs_out_final for step in xrange(int((h_cor - 1) / y1_step)): if step == 0: shift_roi(Icor, 0, 0, w_cor, h_markfull) else: # Don't shift down on first iteration! shift_roi(Icor, 0, y1_step, w_cor, h_markfull) if DEBUG_SAVEIMGS: print_dbg("<><><><> Saving '_Icor_strip.ong' <><><><>") cv.SaveImage("_Icor_strip.png", Icor) pdb.set_trace() # list SYMS := [(str VAL, int X1), ...] syms, params_ = scan_bars.parse_patch(Icor, (w_markfull, h_markfull), gap=H_GAP, LEN=34, orient=scan_bars.HORIZONTAL, MARKTOL=0.7, BEGIN_TOL=0.3, END_TOL=0.3, GAMMA=0.7, idx2tol=idx2tol) decoding = ''.join([t[0] for t in syms]) pix_on, pix_off = params_["pix_on"], params_["pix_off"] def is_pixon_pixoff_ok(): if PIX_ON_OFF_RATIO != None: return (pix_on / pix_off) < PIX_ON_OFF_RATIO else: return True if not sanitycheck_decoding_v2(decoding) or ( not is_pixon_pixoff_ok()): print_dbg("(SanityCheck) FAIL -- '{0}' ({1})".format( decoding, len(decoding))) continue if EXP_PARAMS: global GLOB_PARAMS_ if GLOB_PARAMS_ == None: GLOB_PARAMS_ = {"PIX_ON": [], "PIX_OFF": []} GLOB_PARAMS_["PIX_ON"].append(params_['pix_on']) GLOB_PARAMS_["PIX_OFF"].append(params_['pix_off']) markbbs_rough = [(t[1], 0, t[1] + W_MARK, H_MARK - 1) for t in syms] # Find a tighter y1 for the black marks bbs = tighten_bbs(markbbs_rough, decoding, Icor) # Correct for current-offset in sweep #bbs_out = [(t[1], y1_step*step, t[1] + w_markfull, y1_step*step + h_markfull) for t in syms] bbs_out = [(t[0], t[1] + (y1_step * step), t[2], t[3] + (y1_step * step)) for t in bbs] # Undo rotation correction bbs_out = [to_orig_coords(bb, H_inv) for bb in bbs_out] # Add the compute_border offsets (part1) bbs_out = [(x1 + j1_blk_cor, y1 + i1_blk_cor, x2 + j1_blk_cor, y2 + i1_blk_cor) for (x1, y1, x2, y2) in bbs_out] # Add the compute_border offsets #bbs_out = [(x1+j1_blk, y1+i1_blk, x2+j1_blk, y2+i2_blk) for (x1,y1,x2,y2) in bbs_out] bbs_out = [(x1 + j1_blk, y1 + i1_blk, (x1 + W_MARK - 1) + j1_blk, (y1 + H_MARK - 1) + i1_blk) for (x1, y1, x2, y2) in bbs_out] if DEBUG_SAVEIMGS: print_dbg("==== decoding ({0}): {1}".format( len(decoding), decoding)) Icolor = draw_bbs(imgpath, decoding, bbs_out, isflip) cv.SaveImage("_dbg_showit.png", Icolor) print "<><><><> Saving '_dbg_showit.png' <><><><>" dbg_bbs_out = [(t[1], y1_step * step, t[1] + w_markfull, y1_step * step + h_markfull) for t in syms] # Undo rotation correction dbg_bbs_out = [to_orig_coords(bb, H_inv) for bb in dbg_bbs_out] # Add the compute_border offsets (part1) dbg_bbs_out = [(x1 + j1_blk_cor, y1 + i1_blk_cor, x2 + j1_blk_cor, y2 + i2_blk_cor) for (x1, y1, x2, y2) in dbg_bbs_out] # Add the compute_border offsets dbg_bbs_out = [(x1 + j1_blk, y1 + i1_blk, x2 + j1_blk, y2 + i2_blk) for (x1, y1, x2, y2) in dbg_bbs_out] Icolor_notighten = draw_bbs(imgpath, decoding, dbg_bbs_out, isflip) cv.SaveImage("_dbg_showit_notighten.png", Icolor_notighten) print "<><><><> Saving '_dbg_showit_notighten.png' <><><><>" pdb.set_trace() if sanitycheck_decoding_v2(decoding): candidates.append((decoding, isflip, bbs_out)) if candidates: result = most_popular(candidates, W_MARK=W_MARK, H_MARK=H_MARK) if result != None: break print_dbg("==== Trying another bb_rough") cv.SetImageROI(I, roi_prev) return result
def process_frame(self, frame): frametest = cv.CreateImage(cv.GetSize(frame), 8, 3) binarytest = cv.CreateImage(cv.GetSize(frame), 8, 1) cv.Copy(frame, frametest) cv.SetImageCOI(frametest, 3) cv.Copy(frametest, binarytest) cv.SetImageCOI(frametest, 0) svr.debug("R?", binarytest) # Resize image to 320x240 #copy = cv.CreateImage(cv.GetSize(frame), 8, 3) #cv.Copy(frame, copy) #cv.SetImageROI(frame, (0, 0, 320, 240)) #cv.Resize(copy, frame, cv.CV_INTER_NN) found_gate = False unchanged_frame = cv.CreateImage(cv.GetSize(frame), 8, 3) cv.Copy(frame, unchanged_frame) cv.Smooth(frame, frame, cv.CV_MEDIAN, 7, 7) # Set binary image to have saturation channel hsv = cv.CreateImage(cv.GetSize(frame), 8, 3) binary = cv.CreateImage(cv.GetSize(frame), 8, 1) cv.CvtColor(frame, hsv, cv.CV_BGR2HSV) cv.SetImageCOI(hsv, 1) cv.Copy(hsv, binary) cv.SetImageCOI(hsv, 0) cv.AdaptiveThreshold( binary, binary, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY_INV, self.adaptive_thresh_blocksize, self.adaptive_thresh, ) # Morphology kernel = cv.CreateStructuringElementEx(5, 5, 3, 3, cv.CV_SHAPE_ELLIPSE) cv.Erode(binary, binary, kernel, 1) cv.Dilate(binary, binary, kernel, 1) if self.debug: color_filtered = cv.CloneImage(binary) # Get Edges cv.Canny(binary, binary, 30, 40) # Hough Transform line_storage = cv.CreateMemStorage() raw_lines = cv.HoughLines2(binary, line_storage, cv.CV_HOUGH_STANDARD, rho=1, theta=math.pi / 180, threshold=self.hough_threshold, param1=0, param2=0) # Get vertical lines vertical_lines = [] for line in raw_lines: if line[1] < self.vertical_threshold or \ line[1] > math.pi-self.vertical_threshold: #absolute value does better grouping currently vertical_lines.append((abs(line[0]), line[1])) # Group vertical lines vertical_line_groups = [ ] # A list of line groups which are each a line list for line in vertical_lines: group_found = False for line_group in vertical_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groups.append([line]) # Average line groups into lines vertical_lines = [] for line_group in vertical_line_groups: rhos = map(lambda line: line[0], line_group) angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_lines.append(line) # Get horizontal lines horizontal_lines = [] for line in raw_lines: dist_from_horizontal = (math.pi / 2 + line[1]) % math.pi if dist_from_horizontal < self.horizontal_threshold or \ dist_from_horizontal > math.pi-self.horizontal_threshold: horizontal_lines.append((abs(line[0]), line[1])) # Group horizontal lines horizontal_line_groups = [ ] # A list of line groups which are each a line list for line in horizontal_lines: group_found = False for line_group in horizontal_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: horizontal_line_groups.append([line]) if len(horizontal_line_groups) is 1: self.seen_crossbar = True if self.debug: rhos = map(lambda line: line[0], horizontal_line_groups[0]) angles = map(lambda line: line[1], horizontal_line_groups[0]) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) horizontal_lines = [line] else: self.seen_crossbar = False horizontal_lines = [] self.left_pole = None self.right_pole = None print vertical_lines self.returning = 0 self.found = False if len(vertical_lines) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.returning = (self.left_pole + self.right_pole) / 2 print "Returning ", self.returning if self.last_seen < 0: self.last_center = None self.last_seen = 0 if self.last_center is None: self.last_center = self.returning self.seen_count = 1 elif math.fabs(self.last_center - self.returning) < self.center_trans_thresh: self.seen_count += 1 self.last_seen += 2 else: self.last_seen -= 1 if self.seen_count < self.seen_count_thresh: self.left_pole = None self.right_pole = None else: print "FOUND CENTER AND RETURNED IT" self.found = True else: self.returning = 0 if self.last_seen < 0: self.last_center = None self.last_seen = 0 self.last_seen -= 1 self.left_pole = None self.right_pole = None #TODO: If one pole is seen, is it left or right pole? if self.debug: cv.CvtColor(color_filtered, frame, cv.CV_GRAY2RGB) libvision.misc.draw_lines(frame, vertical_lines) libvision.misc.draw_lines(frame, horizontal_lines) if self.found: cv.Circle(frame, (int(frame.width / 2 + self.returning), int(frame.height / 2)), 15, (0, 255, 0), 2, 8, 0) font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1, 1, 1, 3) cv.PutText(frame, "Gate Sent to Mission Control", (100, 400), font, (255, 255, 0)) print frame.width #cv.ShowImage("Gate", cv.CloneImage(frame)) svr.debug("Gate", cv.CloneImage(frame)) svr.debug("Unchanged", cv.CloneImage(unchanged_frame)) #populate self.output with infos self.output.seen_crossbar = self.seen_crossbar self.output.left_pole = self.left_pole self.output.right_pole = self.right_pole self.return_output() print self
def process_frame(self, frame): (w, h) = cv.GetSize(frame) #generate hue selection frames #create locations for the a pair of test frames frametest = cv.CreateImage(cv.GetSize(frame), 8, 3) binarytest = cv.CreateImage(cv.GetSize(frame), 8, 1) #use the red channel for the binary frame (just for debugging purposes) cv.Copy(frame, frametest) cv.SetImageCOI(frametest, 3) cv.Copy(frametest, binarytest) cv.SetImageCOI(frametest, 0) #reset COI #svr.debug("R?",binarytest) # Resize image to 320x240 #copy = cv.CreateImage(cv.GetSize(frame), 8, 3) #cv.Copy(frame, copy) #cv.SetImageROI(frame, (0, 0, 320, 240)) #cv.Resize(copy, frame, cv.CV_INTER_NN) found_gate = False #create a new frame just for comparison purposes unchanged_frame = cv.CreateImage(cv.GetSize(frame), 8, 3) cv.Copy(frame, unchanged_frame) #apply a course noise filter cv.Smooth(frame, frame, cv.CV_MEDIAN, 7, 7) # Set binary image to have saturation channel hsv = cv.CreateImage(cv.GetSize(frame), 8, 3) binary = cv.CreateImage(cv.GetSize(frame), 8, 1) cv.CvtColor(frame, hsv, cv.CV_BGR2HSV) cv.SetImageCOI(hsv, 1) cv.Copy(hsv, binary) cv.SetImageCOI(hsv, 0) #reset COI #shift hue of image such that orange->red are at top of spectrum ''' binary = libvision.misc.cv_to_cv2(binary) binary = libvision.misc.shift_hueCV2(binary, self.target_shift) binary = libvision.misc.cv2_to_cv(binary) ''' #correct for wraparound on red spectrum #cv.InRange(binary,a_array,b_array,binarytest) #generate mask #cv.Add(binary,cv.fromarray(ones*180),binary,mask=binarytest) #use mask to selectively add values svr.debug("R2?", binary) svr.debug("R2?", binary) #run adaptive threshold for edge detection and more noise filtering cv.AdaptiveThreshold( binary, binary, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY_INV, self.adaptive_thresh_blocksize, self.adaptive_thresh, ) # Morphology kernel = cv.CreateStructuringElementEx(5, 5, 3, 3, cv.CV_SHAPE_ELLIPSE) cv.Erode(binary, binary, kernel, 1) cv.Dilate(binary, binary, kernel, 1) if self.debug: color_filtered = cv.CloneImage(binary) # Get Edges cv.Canny(binary, binary, 30, 40) # Hough Transform line_storage = cv.CreateMemStorage() raw_lines = cv.HoughLines2(binary, line_storage, cv.CV_HOUGH_STANDARD, rho=1, theta=math.pi / 180, threshold=self.hough_threshold, param1=0, param2=0) # Get vertical lines vertical_lines = [] for line in raw_lines: if line[1] < self.vertical_threshold or \ line[1] > math.pi-self.vertical_threshold: #absolute value does better grouping currently vertical_lines.append((abs(line[0]), line[1])) #print message to user for performance purposes logging.debug("{} possibilities reduced to {} lines".format( len(raw_lines), len(vertical_lines))) # Group vertical lines vertical_line_groups = [ ] # A list of line groups which are each a line list i = 0 for line in vertical_lines: group_found = False for line_group in vertical_line_groups: i += 1 if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groups.append([line]) #quick debugging statement logging.debug("{} internal iterations for {} groups".format( i, len(vertical_line_groups))) # Average line groups into lines vertical_lines = [] for line_group in vertical_line_groups: rhos = map(lambda line: line[0], line_group) angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_lines.append(line) #################################################### #vvvv Horizontal line code isn't used for anything # Get horizontal lines horizontal_lines = [] for line in raw_lines: dist_from_horizontal = (math.pi / 2 + line[1]) % math.pi if dist_from_horizontal < self.horizontal_threshold or \ dist_from_horizontal > math.pi-self.horizontal_threshold: horizontal_lines.append((abs(line[0]), line[1])) # Group horizontal lines horizontal_line_groups = [ ] # A list of line groups which are each a line list for line in horizontal_lines: group_found = False for line_group in horizontal_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: horizontal_line_groups.append([line]) if len(horizontal_line_groups) is 1: self.seen_crossbar = True if self.debug: rhos = map(lambda line: line[0], horizontal_line_groups[0]) angles = map(lambda line: line[1], horizontal_line_groups[0]) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) horizontal_lines = [line] else: self.seen_crossbar = False horizontal_lines = [] #^^^ Horizontal line code isn't used for anything ################################################### self.left_pole = None self.right_pole = None #print vertical_lines self.returning = 0 self.found = False if len(vertical_lines) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_lines[0][0], vertical_lines[1][0]), 2) - width / 2 self.returning = (self.left_pole + self.right_pole) / 2 logging.info("Returning {} as gate center delta.".format( self.returning)) #initialize first iteration with 2 known poles if self.last_seen < 0: self.last_center = None self.last_seen = 0 #increment a counter if result is good. if self.last_center is None: self.last_center = self.returning self.seen_count = 1 elif math.fabs(self.last_center - self.returning) < self.center_trans_thresh: self.seen_count += 1 self.last_seen += 2 else: self.last_seen -= 1 #if not conviced, forget left/right pole. Else proclaim success. if self.seen_count < self.seen_count_thresh: self.left_pole = None self.right_pole = None else: print "FOUND CENTER AND RETURNED IT" self.found = True else: self.returning = 0 if self.last_seen < 0: self.last_center = None self.last_seen = 0 self.last_seen -= 1 self.left_pole = None self.right_pole = None #TODO: If one pole is seen, is it left or right pole? if self.debug: cv.CvtColor(color_filtered, frame, cv.CV_GRAY2RGB) libvision.misc.draw_lines(frame, vertical_lines) libvision.misc.draw_lines(frame, horizontal_lines) if self.found: cv.Circle(frame, (int(frame.width / 2 + self.returning), int(frame.height / 2)), 15, (0, 255, 0), 2, 8, 0) font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1, 1, 1, 3) cv.PutText(frame, "Gate Sent to Mission Control", (100, 400), font, (255, 255, 0)) #print frame.width #cv.ShowImage("Gate", cv.CloneImage(frame)) svr.debug("Gate", cv.CloneImage(frame)) svr.debug("Unchanged", cv.CloneImage(unchanged_frame)) #populate self.output with infos self.output.seen_crossbar = self.seen_crossbar self.output.left_pole = self.left_pole self.output.right_pole = self.right_pole self.return_output()
def find_barcode_loc_tm(I, bc_height, TOP_GUARD, BOT_GUARD, TOP_WHITE_PAD, BOT_WHITE_PAD, imgP=None): """ Input: IplImage I: Region where a barcode presumably exists. int BC_HEIGHT: Estimated height of the barcode. Output: list BB. [x1, y1, w, h]. oc_tough_cases/unknown/329_331_25_232_1.png """ w, h = cv.GetSize(I) _ROI = cv.GetImageROI(I) cv.SetImageROI(I, (_ROI[0], _ROI[1], w, h / 2)) top_mats = get_tempmatches(TOP_GUARD, I, T=0.86, do_smooth=True, xwin=3, ywin=3, atleastone=True) cv.SetImageROI(I, _ROI) _ROI = cv.GetImageROI(I) cv.SetImageROI(I, (_ROI[0], _ROI[1] + h / 2, w, h / 2)) bot_mats = get_tempmatches(BOT_GUARD, I, T=0.86, do_smooth=True, xwin=3, ywin=3, atleastone=True) cv.SetImageROI(I, _ROI) # 1.a.) Get top-most/bottom-most match. top_sorted = sorted(top_mats, key=lambda t: t[1]) # (46, 58) bot_sorted = sorted(bot_mats, key=lambda t: -t[1]) # (46, 74) => (46, 401) if not top_sorted and not bot_sorted: if debug: print "...couldn't find either TOP/BOT guard..." return None if top_sorted and bot_sorted: besttop, bestbot = top_sorted[0], bot_sorted[0] # Check that BESTTOP is actually on top of BESTBOT if besttop[1] > bestbot[1]: return None if top_sorted and not bot_sorted: (xtop, ytop, sctop) = top_sorted[0] (xbot, ybot, scbot) = xtop, ytop + bc_height, 1.0 elif bot_sorted and not top_sorted: (xbot, ybot, scbot) = bot_sorted[0] ybot += h / 2 # Account for cropping done above (xtop, ytop, sctop) = xbot, ybot - bc_height, 1.0 else: (xtop, ytop, sctop) = top_sorted[0] (xbot, ybot, scbot) = bot_sorted[0] ybot += h / 2 # Account for cropping done above # 1.b.) Correct for the white-padding from topguard/botguard. ytop += TOP_WHITE_PAD ybot += (BOT_GUARD.height - BOT_WHITE_PAD) # 2.) Try to recover from case where top/bot mat is too high/low. if abs((ybot - ytop) - bc_height) >= (0.1 * bc_height): # Get the more-confident guard match, and work relative to that one if sctop > scbot: ybot = ytop + bc_height else: ytop = ybot - bc_height bb = [min(xtop, xbot), ytop, TOP_GUARD.width, int(abs(ybot - ytop))] return bb
def process_frame(self, frame): self.numpy_frame = libvision.cv_to_cv2(frame) self.debug_frame = self.numpy_frame.copy() self.test_frame = self.numpy_frame.copy() self.numpy_frame = cv2.medianBlur(self.numpy_frame, 7) self.numpy_frame = cv2.cvtColor(self.numpy_frame, cv2.COLOR_BGR2HSV) (rf1, rf2, rf3) = cv2.split(self.numpy_frame) Rbinary = rf3 Gbinary = rf1 # Adaptive Threshold Rbinary = cv2.adaptiveThreshold(Rbinary, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, self.adaptive_thresh_blocksize, self.adaptive_thresh) Gbinary = cv2.adaptiveThreshold(Gbinary, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, self.Gadaptive_thresh_blocksize, self.Gadaptive_thresh) # Morphology kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) Rbinary = cv2.erode(Rbinary, kernel) Rbinary = cv2.dilate(Rbinary, kernel) Gbinary = cv2.erode(Gbinary, kernel) Gbinary = cv2.dilate(Gbinary, kernel) Rframe = cv2.cvtColor(Rbinary, cv2.COLOR_GRAY2RGB) Gframe = cv2.cvtColor(Gbinary, cv2.COLOR_GRAY2RGB) # Hough Transform raw_linesG = cv2.HoughLines(Gbinary, rho=1, theta=math.pi / 180, threshold=self.hough_thresholdG) # Get vertical lines vertical_linesG = [] if raw_linesG is None: raw_linesG = [] if len(raw_linesG) > 0: for line in raw_linesG[0]: rho = line[0] theta = line[1] if theta < self.vertical_thresholdG or theta > ( math.pi - self.vertical_thresholdG): vertical_linesG.append((rho, theta)) # Group vertical lines vertical_line_groupsG = [ ] # A list of line groups which are each a line list for line in vertical_linesG: #print "Green Line Grouping Possibility:", line[0], ", ", line[1] group_found = False for line_group in vertical_line_groupsG: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groupsG.append([line]) # Average line groups into lines vertical_linesG = [] for line_group in vertical_line_groupsG: rhos = map(lambda line: line[0], line_group) angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_linesG.append(line) # Get horizontal lines horizontal_lines = [] if len(raw_linesG) > 0: for line in raw_linesG[0]: rho = line[0] theta = line[1] dist_from_horizontal = (math.pi / 2 + line[1]) % math.pi if dist_from_horizontal < self.horizontal_threshold or dist_from_horizontal > math.pi - self.horizontal_threshold: horizontal_lines.append((abs(line[0]), line[1])) # Group horizontal lines horizontal_line_groups = [ ] # A list of line groups which are each a line list for line in horizontal_lines: group_found = False for line_group in horizontal_line_groups: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: horizontal_line_groups.append([line]) if len(horizontal_line_groups) is 1: self.seen_crossbar = True rhos = map(lambda line: line[0], horizontal_line_groups[0]) angles = map(lambda line: line[1], horizontal_line_groups[0]) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) horizontal_lines = [line] else: self.seen_crossbar = False horizontal_lines = [] self.left_pole = None self.right_pole = None Rframe = libvision.cv2_to_cv(Rframe) Gframe = libvision.cv2_to_cv(self.debug_frame) Rbinary = libvision.cv2_to_cv(Rbinary) self.debug_frame = libvision.cv2_to_cv(self.debug_frame) self.test_frame = libvision.cv2_to_cv(self.test_frame) Gbinary = libvision.cv2_to_cv(Gbinary) if len(vertical_linesG) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_linesG[0][0], vertical_linesG[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_linesG[0][0], vertical_linesG[1][0]), 2) - width / 2 # TODO: If one pole is seen, is it left or right pole? # Calculate planar distance r (assuming we are moving perpendicular to # the hedge) if self.left_pole and self.right_pole: theta = abs(self.left_pole - self.right_pole) self.r = 3 / math.tan(math.radians(theta / 2)) else: self.r = None if self.r and self.seen_crossbar: bar_phi = (-1 * horizontal_lines[0][0] + Gframe.height / 2) / (Gframe.height / 2) * 32 self.crossbar_depth = self.r * math.atan(math.radians(bar_phi)) else: self.crossbar_depth = None # Line Finding on Red pvc # Hough Transform line_storage = cv.CreateMemStorage() raw_linesR = cv.HoughLines2(Rbinary, line_storage, cv.CV_HOUGH_STANDARD, rho=1, theta=math.pi / 180, threshold=self.hough_thresholdR, param1=0, param2=0) # Get vertical lines vertical_linesR = [] for line in raw_linesR: if line[1] < self.vertical_thresholdR or \ line[1] > math.pi - self.vertical_thresholdR: vertical_linesR.append((abs(line[0]), line[1])) # Group vertical lines vertical_line_groupsR = [ ] # A list of line groups which are each a line list for line in vertical_linesR: group_found = False for line_group in vertical_line_groupsR: if line_group_accept_test(line_group, line, self.max_range): line_group.append(line) group_found = True if not group_found: vertical_line_groupsR.append([line]) # Average line groups into lines vertical_linesR = [] for line_group in vertical_line_groupsR: rhos = map(lambda line: line[0], line_group) angles = map(lambda line: line[1], line_group) line = (sum(rhos) / len(rhos), circular_average(angles, math.pi)) vertical_linesR.append(line) ''' for red_line in vertical_linesR: print "Red Line:", red_line[0],", ",red_line[1] for green_line in vertical_linesG: print "Green Line:", green_line[0],", ",green_line[1] ''' for red_line in vertical_linesR: for green_line in vertical_linesG[:]: if math.fabs(green_line[0] - red_line[0]) < self.GR_Threshold0 and \ math.fabs(green_line[1] - red_line[1]) < self.GR_Threshold1: vertical_linesG.remove(green_line) for red_line in vertical_linesR: print "New Red Line:", red_line[0], ", ", red_line[1] for green_line in vertical_linesG: print "New Green VLine:", green_line[0], ", ", green_line[1] for green_line in horizontal_lines: print "New Green HLine:", green_line[0], ", ", green_line[1] if len(vertical_linesR) is 0: print "No Red Found" self.left_pole = None self.right_pole = None if len(vertical_linesR) is 2: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] self.left_pole = round( min(vertical_linesR[0][0], vertical_linesR[1][0]), 2) - width / 2 self.right_pole = round( max(vertical_linesR[0][0], vertical_linesR[1][0]), 2) - width / 2 # TODO: If one pole is seen, is it left or right pole? # Calculate planar distance r (assuming we are moving perpendicular to # the hedge) if self.left_pole and self.right_pole: theta = abs(self.left_pole - self.right_pole) self.r = 3 / math.tan(math.radians(theta / 2)) else: self.r = None for i in range(len(vertical_linesR[:])): if vertical_linesR[i][1] > math.pi / 2: vertical_linesR[i] = (vertical_linesR[i][0], -(math.pi - vertical_linesR[i][1])) print "Line changed to ", vertical_linesR[i] for line in vertical_linesR: print line if line[1] > math.pi / 2: line = (line[0], math.pi - line[1]) print "Line changed to ", line libvision.misc.draw_lines(Gframe, vertical_linesG) libvision.misc.draw_lines(Gframe, horizontal_lines) libvision.misc.draw_lines(Rframe, vertical_linesR) # there was a merge error, these 3 lines conflicted b/c your copy out of date for line in vertical_linesR: roi = cv.GetImageROI(frame) width = roi[2] height = roi[3] x = line[0] * math.cos(line[1]) y = line[0] * math.sin(line[1]) cv.Circle(Rframe, (int(x), int(y)), 5, (0, 255, 0), -1, 8, 0) if x > width or y > width or x < 0 or y < 0: print "Lost point ", x svr.debug("Original", self.test_frame) svr.debug("Red", Rframe) svr.debug("Green", Gframe) svr.debug("Green Binary", Gbinary)