def half_line(corners): """Divides a quadrilateral in half. The argument `corners` is a list of four points (tuples of (x, y)), representing the corners of a quadrilateral. The list may start on any of the four corners, but must go around the quadrilateral in clockwise or counter-clockwise order; skipping around is not allowed. The function returns a line (a list of two points) that joins the midpoints of two oposite sides of the quadrilateral defined by the four passed-in corners. Arbitrarily, the bisected sides are the one joining corner 0 and corner 1, and the one joining corner 2 and corner 3.""" c = center(corners) # `d` is the perspective vanishing point for the two sides that # we're *not* bisecting. d = intersection(line(corners[0], corners[3]), line(corners[1], corners[2])) if not d: # No vanishing point found: the two sides must be parallel. # So just use one of the sides as the direction. This adds # the vector from corner[3] to corner[0] to the center point we # computed above. d = (c[0] + corners[0][0] - corners[3][0], c[1] + corners[0][1] - corners[3][1]) l = line(c, d) p1 = intersection(l, line(corners[0], corners[1])) p2 = intersection(l, line(corners[2], corners[3])) return (p1, p2)
def closest_node_on_segment_to_node(node, segment) -> Node.Node: A_start, B_start, C_start = perpendicular(segment.start, segment) A_end, B_end, C_end = perpendicular(segment.end, segment) if line_value(A_start, B_start, C_start, node) * line_value( A_end, B_end, C_end, node) < 0: node_A, node_B, node_C = perpendicular(node, segment) x = 10000 y = (-node_A * x - node_C) / node_B end = Node.Node(x, y) node_segment = Edge.Edge(node, end) if geometry.intersect(segment, node_segment): closest_node = geometry.intersection(segment, node_segment) else: x = -10000 y = (-node_A * x - node_C) / node_B end = Node.Node(x, y) node_segment = Edge.Edge(node, end) closest_node = geometry.intersection(segment, node_segment) else: closest_node = segment.start distance_to_start = dist(node, segment.start) distance_to_end = dist(node, segment.end) if distance_to_start > distance_to_end: closest_node = segment.end return closest_node
def estimate(o_): r = [] o = list(o_) o.append(o[0]) res = [] for i in range(0, len(o) - 1): o1 = o[i] o2 = o[i + 1] p1, p2 = intersection(o1, o2) if p1 is not None: r.append((p1, p2)) else: p1, p2 = closest_non_intersecting(o1, o2) res.append(average([p1, p2])) r.append(r[0]) for i in range(0, int(len(o_) / 2)): o1 = o[i] o2 = o[i + int(len(o_) / 2)] p1, p2 = intersection(o1, o2) if p1 is not None: r.append((p1, p2)) else: p1, p2 = closest_non_intersecting(o1, o2) res.append(average([p1, p2])) for i in range(0, len(r) - 1): aux = [r[i][0], r[i][1], r[i + 1][0], r[i + 1][1]] p1, p2 = closest_pair(aux) if p1 is not None and p2 is not None: res.append(average([p1, p2])) return average(res)
def half_line(corners): # TODO what is this? c = center(corners) d = intersection(line(corners[0], corners[3]), line(corners[1], corners[2])) if d: l = line(c, d) else: l = line(c, (c[0] + corners[0][0] - corners[3][0], c[1] + corners[0][1] - corners[3][1])) p1 = intersection(l, line(corners[0], corners[1])) p2 = intersection(l, line(corners[2], corners[3])) return (p1, p2)
def compare(a: Union[Point, Segment], b: Union[Point, Segment]): # get current ray ray = ray_getter() if isinstance(a, Point) and isinstance(b, Point): return dist(ray.p1, a) - dist(ray.p2, b) if isinstance(a, Point) and isinstance(b, Segment): pb = intersection(*ray, *b, restriction_1='ray', restriction_2='segment') dist_a = dist(ray.p1, a) dist_b = dist(ray.p1, pb) if dist_a == dist_b: return -1 return dist_a - dist_b if isinstance(a, Segment) and isinstance(b, Point): pa = intersection(*ray, *a, restriction_1='ray', restriction_2='segment') dist_a = dist(ray.p1, pa) dist_b = dist(ray.p1, b) if dist_a == dist_b: return 1 return dist_a - dist_b if isinstance(a, Segment) and isinstance(b, Segment): pa = intersection(*ray, *a, restriction_1='ray', restriction_2='segment') pb = intersection(*ray, *b, restriction_1='ray', restriction_2='segment') dist_a = dist(ray.p1, pa) dist_b = dist(ray.p1, pb) if dist_a == dist_b: pa2 = a.p1 if a.p2 == pa else a.p2 pb2 = b.p1 if b.p2 == pb else b.p2 return angle_between_points(ray.p1, ray.p2, pa2) - angle_between_points( ray.p1, ray.p2, pb2) return dist_a - dist_b raise ValueError( f'Comparator got unexpected types: {type(a)}, {type(b)}')
def _draw_beachline(e, beachline): #print beachline.T.dumps() for arc in beachline: end,start=None,None # plot intersections if beachline.predecessor(arc): #print 'waaat', type(beachline.predecessor(arc)) start = intersection(beachline.predecessor(arc).site,arc.site,e.y) plt.plot(start[0],start[1],'o',color='black') if beachline.sucessor(arc): #print 'waaat', type(beachline.sucessor(arc)) end = intersection(arc.site,beachline.sucessor(arc).site,e.y) plt.plot(end[0],end[1],'o',color='black') plot_parabola(arc.site,e.y,endpoints=[start,end],color='purple')
def visibility_graph_brute(collection: Collection) -> Collection: """ Generates visibility graph in O(n^3) """ # create graph graph = Collection(points=collection.all_points) # get all segments segments = collection.all_segments # get polygons for each point polygons = defaultdict(list) for poly in collection.polygons: for p in poly.points: polygons[p].append(poly) # for each pair of points for p1, p2 in combinations(collection.all_points, 2): s = Segment(p1, p2) # if this segment is a diagonal of polygon ignore it # if is_diagonal(s, polygons): # continue # if segment intersects with any other segment if any( intersection(*s, *seg, restriction_1='segment', restriction_2='segment') for seg in segments if (p1 not in seg) and (p2 not in seg) ): continue # add to graph graph.segments.add(s) return graph
def transform( wheel1: Point, wheel2: Point, tail: Point, scene_center: Point, ): """ :return: ( robot_position, # position against scene center; angle, # angle against scene center; distance, # distance to scene center; ) """ robot_center = midpoint(wheel1, wheel2) # finds the tail point's prime and its projection line - the main one tail_prime = two_points_90(wheel1, robot_center) intersection_line = line(wheel1, wheel2) if not pts_same_side(tail, tail_prime, intersection_line): tail_prime = two_points_90(wheel2, robot_center) main_projection_line = line(tail, tail_prime) # finds center line's prime center_line = line(scene_center, robot_center) side_line = line(tail, wheel1) side_intersection = intersection(center_line, side_line) if side_intersection: side_line_prime = line(tail_prime, wheel1) else: side_line = line(tail, wheel2) side_intersection = intersection(center_line, side_line) side_line_prime = line(tail_prime, wheel2) # noinspection PyTypeChecker side_intersection_projection_line = parallel_line(main_projection_line, side_intersection) side_intersection_prime = intersection(side_line_prime, side_intersection_projection_line) center_line_prime = line(robot_center, side_intersection_prime) # computes position, angle and distance center_line_projection = parallel_line(main_projection_line, scene_center) center_prime = intersection(center_line_projection, center_line_prime) dist = distance(center_prime, robot_center) / distance(robot_center, tail_prime) robot_position = robot_center - center_prime angle = math.degrees(normalize_angle( three_pts_angle(tail_prime, robot_center, center_prime) - math.pi)) return Object(robot_position, angle, (dist * ROBOT_UNIT))
def _lines(corners, n): # TODO what is this? if n == 0: x = half_line(corners) return (_lines([corners[0], x[0], x[1], corners[3]], 1) + [x] + _lines([x[0], corners[1], corners[2], x[1]], 1)) else: x = half_line(corners) c = intersection(line(x[0], corners[2]), line(corners[1], corners[3])) d = intersection(line(corners[0], corners[3]), line(corners[1], corners[2])) if d: l = (intersection(line(corners[0], corners[1]), line(c, d)), intersection(line(corners[2], corners[3]), line(c, d))) else: lx = line(c, (c[0] + corners[0][0] - corners[3][0], c[1] + corners[0][1] - corners[3][1])) l = (intersection(line(corners[0], corners[1]), lx), intersection(line(corners[2], corners[3]), lx)) l2 = half_line([corners[0], l[0], l[1], corners[3]]) if n == 1: return ([l, l2] + _lines([l[0], l2[0], l2[1], l[1]], 2) + _lines([corners[0], l2[0], l2[1], corners[3]], 2) + _lines([l[0], corners[1], corners[2], l[1]], 2)) if n == 2: return [l, l2]
def merge_square_contours(cnts, width, height): """ Merge overlapping contours. Only contours fully containing smaller contours are not merged. Processing each contour as a bounding box to perform union, contains and intersection operations. :param cnts: list of square contours :param width: width of the original image :param height: height of the original image :return: list of merged contours sorted by ranking """ rects = [] for cnt in cnts: rect = cv2.boundingRect(cnt) rects.append(rect) k = 0 merged_squares = [] while k < len(rects) - 1: if contains(rects[k], rects[k + 1]): merged_squares.append(rects[k]) k += 1 elif intersection(rects[k], rects[k + 1]) is not None: u = union(rects[k], rects[k + 1]) new_rect = list([u[0], u[1], u[2], u[3]]) rects[k + 1] = new_rect k += 1 if k == len(rects) - 1: merged_squares.append(new_rect) else: merged_squares.append(rects[k]) k += 1 if k == len(rects) - 1: merged_squares.append(rects[k]) np_merged_squares = [] # transform squares back to contours for msq in merged_squares: np_merged_squares.append( np.array([[msq[0], msq[1]], [msq[0] + msq[2], msq[1]], [msq[0] + msq[2], msq[1] + msq[3]], [msq[0], msq[1] + msq[3]]])) sorted_merged_squares = sorted( np_merged_squares, key=lambda square: rank(square, width, height)) return sorted_merged_squares
def distance_node_to_segment(node: Node.Node, segment: Edge.Edge): # distance between node and segment, return min distance and closest point on segment to the node A_start, B_start, C_start = perpendicular(segment.start, segment) A_end, B_end, C_end = perpendicular(segment.end, segment) if line_value(A_start, B_start, C_start, node) * line_value( A_end, B_end, C_end, node) < 0: distance = abs( line_value(segment.A, segment.B, segment.C, node) / sqrt(segment.A**2 + segment.B**2)) node_A, node_B, node_C = perpendicular(node, segment) x = 10000 y = (-node_A * x - node_C) / node_B end = Node.Node(x, y) node_segment = Edge.Edge(node, end) if geometry.intersect(segment, node_segment): closest_node = geometry.intersection(segment, node_segment) else: distance = min(dist(node, segment.start), dist(node, segment.end)) return distance
def visible_vertices(point: Point, points: Iterable[Point], segments: Dict[Point, List[Segment]]) -> Iterator[Point]: """ Yields points from given points that can be seen from given start point. """ # remove point from points points = filter(lambda x: x != point, points) # sort points first by angle and then by distance from point points = sorted(points, key=lambda x: (angle_to_xaxis(point, x), dist(point, x))) # create sorted list from segments that cross starting ray # list is sorted using ray that has to be updated ray = Segment(point, Point(point.x + 1, point.y)) status = SortedList( iterable=(seg for seg in set(chain(*segments.values())) if intersection( *ray, *seg, restriction_1='ray', restriction_2='segment') and point not in seg), key=status_key(lambda: ray)) # for each point (they are sorted by angle) for p in points: # update ray ray = Segment(point, p) # if p is visible yield it if status.bisect_left(p) == 0: yield p # remove segments from this point for seg in segments[p]: if orient(point, p, seg.p1 if seg.p2 == p else seg.p2) < 0: status.remove(seg) # add segments to this point for seg in segments[p]: if orient(point, p, seg.p1 if seg.p2 == p else seg.p2) > 0: status.add(seg)
def _lines(corners, n): # `mid_line` is a line that joins the midpoints of two oposite sides # of the quadrilateral defined by the four passed-in corners. mid_line = half_line(corners) # TODO what is this? if n == 0: # This recurses to look at the part of the quadrilateral on # *one* side of `mid_line`. Returns all lines on that side, # not including `mid_line` but including the other edge. l0 = _lines([corners[0], mid_line[0], mid_line[1], corners[3]], 1) # This is just the mid-line. l1 = [mid_line] # This recurses to look at the part of the quadrilateral on the # *other* side of `mid_line`. Returns all lines on that side, # not including `mid_line` but including the other edge. l2 = _lines([mid_line[0], corners[1], corners[2], mid_line[1]], 1) return (l0 + l1 + l2) else: c = intersection(line(mid_line[0], corners[2]), line(corners[1], corners[3])) d = intersection(line(corners[0], corners[3]), line(corners[1], corners[2])) if d: l = (intersection(line(corners[0], corners[1]), line(c, d)), intersection(line(corners[2], corners[3]), line(c, d))) else: lx = line(c, (c[0] + corners[0][0] - corners[3][0], c[1] + corners[0][1] - corners[3][1])) l = (intersection(line(corners[0], corners[1]), lx), intersection(line(corners[2], corners[3]), lx)) l2 = half_line([corners[0], l[0], l[1], corners[3]]) if n == 1: return ([l, l2] + _lines([l[0], l2[0], l2[1], l[1]], 2) + _lines([corners[0], l2[0], l2[1], corners[3]], 2) + _lines([l[0], corners[1], corners[2], l[1]], 2)) if n == 2: return [l, l2]
def app(input_file, output_file): gauge = process_image.Gauge() host = housekeeping.OS() # setup image reuse_circle = housekeeping.test_time() im = host.get_image(DEF.SAMPLE_PATH, input_file) gray_im = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) prep = gray_im # copy of grayscale image to be preprocessed for angle detection mask = np.zeros_like(prep) canvas = np.zeros_like(im) # output image np.copyto(canvas, im) error_screen = np.zeros_like(im) height, width = gray_im.shape assert height == DEF.HEIGHT assert width == DEF.WIDTH # mask_bandpass is a mask of the gauge obtained from histogram peaks hist0, mask_bandpass = hist_an.bandpass(gray_im) # prep is binary image ready for line detection prep = process_image.blur_n_threshold(prep, do_blur=1) prep = process_image.erode_n_dilate(prep) # host.write_image(("mask_bandpass.jpg", mask_bandpass)) # Hough transforms if reuse_circle: print "reusing previous circle" circle_x, circle_y, radius = housekeeping.return_circle() circle_x = int(circle_x) circle_y = int(circle_y) else: circles = hough_transforms.hough_c(gray_im) for c in circles[:1]: # scale factor makes applicable area slightly larger just to be safe we are not missing anything cv2.circle(mask, (c[0], c[1]), int(c[2] * DEF.CIRCLE_SCALE_FACTOR), (255, 255, 255), -1) prep = cv2.bitwise_and(prep, mask) cv2.circle(canvas, (c[0], c[1]), c[2], (0, 255, 0), DEF.THICKNESS) circle_x = c[0] circle_y = c[1] radius = int(c[2]) cv2.circle(mask, (int(circle_x), int(circle_y)), int(radius * DEF.CIRCLE_SCALE_FACTOR), (255, 255, 255), -1) cv2.circle(canvas, (int(circle_x), int(circle_y)), radius, (0, 255, 0), DEF.THICKNESS) cv2.circle(canvas, (int(circle_x), int(circle_y - 12)), 25, (0, 255, 0), DEF.THICKNESS) prep = cv2.bitwise_and(prep, mask) prep = cv2.bitwise_and(mask_bandpass, prep) thresholded = np.copy(prep) prep = process_image.find_contour(prep, draw=True) lines = hough_transforms.hough_l(prep) for line in lines[:10]: for (rho, theta) in line: # blue for infinite lines (only draw the 2 strongest) x0 = np.cos(theta) * rho y0 = np.sin(theta) * rho pt1 = (int(x0 + (height + width) * (-np.sin(theta))), int(y0 + (height + width) * np.cos(theta))) pt2 = (int(x0 - (height + width) * (-np.sin(theta))), int(y0 - (height + width) * np.cos(theta))) gauge.lines.append((pt1, pt2)) gauge.angles_in_radians.append(theta) gauge.angles_in_degrees.append(geometry.rad_to_degrees(theta)) # cv2.line(canvas, pt1, pt2, (255, 255, 0), DEF.THICKNESS / 3) # check standard deviation of angles to catch angle wrap-around (359 to 0) angle_std = np.std(gauge.angles_in_degrees) if angle_std > 50: for i in range(len(gauge.angles_in_degrees)): if gauge.angles_in_degrees[i] < 20: gauge.angles_in_degrees[i] += 180 gauge.angles_in_radians[i] += np.pi angle_index = geometry.get_angles(gauge.angles_in_degrees) if len(gauge.lines) < 2: EX.error_output(error_screen, err_msg="unable to find needle from lines") sys.exit("unable to find needle form lines") line_found = False for this_pair in angle_index: # print "angle1: ", gauge.angles_in_degrees[this_pair[0]] # print "angle2: ", gauge.angles_in_degrees[this_pair[1]] print this_pair line1 = geometry.make_line(gauge.lines[this_pair[0]]) line2 = geometry.make_line(gauge.lines[this_pair[1]]) intersecting_pt = geometry.intersection(line1, line2) if intersecting_pt is not None: print "Intersection detected:", intersecting_pt cv2.circle(canvas, intersecting_pt, 10, DEF.RED, 3) else: print "No single intersection point detected" # Although we found a line coincident with the gauge needle, # we need to find which of the two direction it is pointing # guess1 and guess2 are 180 degrees apart avg_theta = (gauge.angles_in_radians[this_pair[0]] + gauge.angles_in_radians[this_pair[1]]) / 2 guess1 = [avg_theta, (0, 0)] guess2 = [avg_theta + np.pi, (0, 0)] if guess2[0] > 2 * np.pi: # in case adding pi made it greater than 2pi guess2[0] -= 2 * np.pi print "guess1: ", guess1[0] print "guess2: ", guess2[0] guess1[1] = (int(circle_x + radius * np.sin(guess1[0])), int(circle_y - radius * np.cos(guess1[0]))) guess2[1] = (int(circle_x + radius * np.sin(guess2[0])), int(circle_y - radius * np.cos(guess2[0]))) # find the distance between our guess and intersection of gauge needle lines # the guess that is closer to the intersection is the correct one dist1 = math.hypot(intersecting_pt[0] - guess1[1][0], intersecting_pt[1] - guess1[1][1]) dist2 = math.hypot(intersecting_pt[0] - guess2[1][0], intersecting_pt[1] - guess2[1][1]) print "dist1: ", dist1 print "dist2: ", dist2 if dist1 < DEF.MAX_DISTANCE or dist2 < DEF.MAX_DISTANCE: line_found = True if dist1 < dist2: correct_guess = guess1 else: correct_guess = guess2 if line_found is True: cv2.circle(canvas, guess1[1], 10, DEF.GREEN, 3) cv2.circle(canvas, guess2[1], 10, DEF.BLUE, 3) # cv2.line(canvas, gauge.lines[this_pair[0]][0], gauge.lines[this_pair[0]][1], (255, 0, 0), # DEF.THICKNESS) # cv2.line(canvas, gauge.lines[this_pair[1]][0], gauge.lines[this_pair[1]][1], (255, 0, 0), # DEF.THICKNESS) break if line_found is False: EX.error_output(error_screen, err_msg="no positive pair") needle_angle = 0.0 else: ref_offset = np.pi needle_angle = geometry.rad_to_degrees(correct_guess[0] - ref_offset) if needle_angle < 0.0: needle_angle += 360 print "original_guess: ", needle_angle angle_adjustment_set = np.arange(needle_angle - 5.0, needle_angle + 5.0, 0.1) sum_pixels = [] for adj_angle in angle_adjustment_set: gauge.update_needle(adj_angle) gauge.get_needle((circle_x, circle_y - 10)) overlap = cv2.bitwise_and(thresholded, gauge.needle_canvas) sum_pixels.append(np.sum(overlap / 255)) adjustment_index = sum_pixels.index(max(sum_pixels)) needle_angle = angle_adjustment_set[adjustment_index] gauge.update_needle(needle_angle) gauge.get_needle((circle_x, circle_y - 10)) needle_rgb = cv2.cvtColor(gauge.needle_canvas, cv2.COLOR_GRAY2BGR) canvas = cv2.add(canvas, needle_rgb / 2) print "updated_guess: ", needle_angle pressure = np.interp( needle_angle, [DEF.GAUGE_MIN['angle'], DEF.GAUGE_MAX['angle']], [DEF.GAUGE_MIN['pressure'], DEF.GAUGE_MAX['pressure']]) pressure_str = str(round(pressure, 2)) print "pressure = ", pressure display_values(canvas, pressure_str) final_line_pt1 = ( int(circle_x + radius * np.sin(geometry.degrees_to_radians(needle_angle))), int(circle_y - radius * np.cos(geometry.degrees_to_radians(needle_angle)))) final_line_pt2 = ( int(circle_x + radius * np.sin(geometry.degrees_to_radians(needle_angle + 180))), int(circle_y - radius * np.cos(geometry.degrees_to_radians(needle_angle + 180)))) cv2.line(canvas, final_line_pt1, final_line_pt2, DEF.RED, thickness=DEF.THICKNESS * 2) prep = cv2.bitwise_and(prep, mask) # plt.subplot(231) # plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB)) # plt.subplot(232) # plt.imshow(255 - mask_bandpass, 'gray') # plt.subplot(233) # plt.imshow(prep, 'gray') # plt.subplot(234) # plt.imshow(cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB)) # plt.subplot(235) # plt.plot(hist0) # plt.xlim([0, 256]) # plt.ylim([0, 50000]) # plt.show() cv2.circle(prep, (circle_x, circle_y), 25, (0, 255, 0), DEF.THICKNESS) prep = cv2.cvtColor(prep, cv2.COLOR_GRAY2BGR) canvas = np.concatenate((im, canvas), axis=1) host.write_to_file('w', "Pressure: " + pressure_str + " MPa", "Temperature: " + str(host.read_temp())) host.write_to_file('a', "circle_x:" + str(circle_x), "circle_y:" + str(circle_y), "radius:" + str(radius)) # pass in tuples ("filename.ext", img_to_write) image_path = re.sub('file', str(output_file), DEF.OUTPUT_PATH) host.write_image((image_path, canvas)) image_path = re.sub('file', str(output_file), DEF.THRESH_PATH) host.write_image((image_path, thresholded))
def key(self,directrix): if self.q is None: return self.p[0] else: return intersection(self.p, self.q, directrix)[0]
def center(corners): """Given a list of four corner points, return the center of the square.""" return intersection(line(corners[0], corners[2]), line(corners[1], corners[3]))
def app(input_file, output_file): gauge = process_image.Gauge() host = housekeeping.OS() # setup image reuse_circle = housekeeping.test_time() im = host.get_image(DEF.SAMPLE_PATH, input_file) gray_im = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) prep = gray_im # copy of grayscale image to be preprocessed for angle detection mask = np.zeros_like(prep) canvas = np.zeros_like(im) # output image np.copyto(canvas, im) error_screen = np.zeros_like(im) height, width = gray_im.shape assert height == DEF.HEIGHT assert width == DEF.WIDTH # mask_bandpass is a mask of the gauge obtained from histogram peaks hist0, mask_bandpass = hist_an.bandpass(gray_im) # prep is binary image ready for line detection prep = process_image.blur_n_threshold(prep, do_blur=1) prep = process_image.erode_n_dilate(prep) # host.write_image(("mask_bandpass.jpg", mask_bandpass)) # Hough transforms if reuse_circle: print "reusing previous circle" circle_x, circle_y, radius = housekeeping.return_circle() circle_x = int(circle_x) circle_y = int(circle_y) else: circles = hough_transforms.hough_c(gray_im) for c in circles[:1]: # scale factor makes applicable area slightly larger just to be safe we are not missing anything cv2.circle(mask, (c[0], c[1]), int(c[2] * DEF.CIRCLE_SCALE_FACTOR), (255, 255, 255), -1) prep = cv2.bitwise_and(prep, mask) cv2.circle(canvas, (c[0], c[1]), c[2], (0, 255, 0), DEF.THICKNESS) circle_x = c[0] circle_y = c[1] radius = int(c[2]) cv2.circle(mask, (int(circle_x), int(circle_y)), int(radius * DEF.CIRCLE_SCALE_FACTOR), (255, 255, 255), -1) cv2.circle(canvas, (int(circle_x), int(circle_y)), radius, (0, 255, 0), DEF.THICKNESS) cv2.circle(canvas, (int(circle_x), int(circle_y-12)), 25, (0, 255, 0), DEF.THICKNESS) prep = cv2.bitwise_and(prep, mask) prep = cv2.bitwise_and(mask_bandpass, prep) thresholded = np.copy(prep) prep = process_image.find_contour(prep, draw=True) lines = hough_transforms.hough_l(prep) for line in lines[:10]: for (rho, theta) in line: # blue for infinite lines (only draw the 2 strongest) x0 = np.cos(theta) * rho y0 = np.sin(theta) * rho pt1 = (int(x0 + (height + width) * (-np.sin(theta))), int(y0 + (height + width) * np.cos(theta))) pt2 = (int(x0 - (height + width) * (-np.sin(theta))), int(y0 - (height + width) * np.cos(theta))) gauge.lines.append((pt1, pt2)) gauge.angles_in_radians.append(theta) gauge.angles_in_degrees.append(geometry.rad_to_degrees(theta)) # cv2.line(canvas, pt1, pt2, (255, 255, 0), DEF.THICKNESS / 3) # check standard deviation of angles to catch angle wrap-around (359 to 0) angle_std = np.std(gauge.angles_in_degrees) if angle_std > 50: for i in range(len(gauge.angles_in_degrees)): if gauge.angles_in_degrees[i] < 20: gauge.angles_in_degrees[i] += 180 gauge.angles_in_radians[i] += np.pi angle_index = geometry.get_angles(gauge.angles_in_degrees) if len(gauge.lines) < 2: EX.error_output(error_screen, err_msg="unable to find needle from lines") sys.exit("unable to find needle form lines") line_found = False for this_pair in angle_index: # print "angle1: ", gauge.angles_in_degrees[this_pair[0]] # print "angle2: ", gauge.angles_in_degrees[this_pair[1]] print this_pair line1 = geometry.make_line(gauge.lines[this_pair[0]]) line2 = geometry.make_line(gauge.lines[this_pair[1]]) intersecting_pt = geometry.intersection(line1, line2) if intersecting_pt is not None: print "Intersection detected:", intersecting_pt cv2.circle(canvas, intersecting_pt, 10, DEF.RED, 3) else: print "No single intersection point detected" # Although we found a line coincident with the gauge needle, # we need to find which of the two direction it is pointing # guess1 and guess2 are 180 degrees apart avg_theta = (gauge.angles_in_radians[this_pair[0]] + gauge.angles_in_radians[this_pair[1]]) / 2 guess1 = [avg_theta, (0, 0)] guess2 = [avg_theta + np.pi, (0, 0)] if guess2[0] > 2 * np.pi: # in case adding pi made it greater than 2pi guess2[0] -= 2 * np.pi print "guess1: ", guess1[0] print "guess2: ", guess2[0] guess1[1] = (int(circle_x + radius * np.sin(guess1[0])), int(circle_y - radius * np.cos(guess1[0]))) guess2[1] = (int(circle_x + radius * np.sin(guess2[0])), int(circle_y - radius * np.cos(guess2[0]))) # find the distance between our guess and intersection of gauge needle lines # the guess that is closer to the intersection is the correct one dist1 = math.hypot(intersecting_pt[0] - guess1[1][0], intersecting_pt[1] - guess1[1][1]) dist2 = math.hypot(intersecting_pt[0] - guess2[1][0], intersecting_pt[1] - guess2[1][1]) print "dist1: ", dist1 print "dist2: ", dist2 if dist1 < DEF.MAX_DISTANCE or dist2 < DEF.MAX_DISTANCE: line_found = True if dist1 < dist2: correct_guess = guess1 else: correct_guess = guess2 if line_found is True: cv2.circle(canvas, guess1[1], 10, DEF.GREEN, 3) cv2.circle(canvas, guess2[1], 10, DEF.BLUE, 3) # cv2.line(canvas, gauge.lines[this_pair[0]][0], gauge.lines[this_pair[0]][1], (255, 0, 0), # DEF.THICKNESS) # cv2.line(canvas, gauge.lines[this_pair[1]][0], gauge.lines[this_pair[1]][1], (255, 0, 0), # DEF.THICKNESS) break if line_found is False: EX.error_output(error_screen, err_msg="no positive pair") needle_angle = 0.0 else: ref_offset = np.pi needle_angle = geometry.rad_to_degrees(correct_guess[0] - ref_offset) if needle_angle < 0.0: needle_angle += 360 print "original_guess: ", needle_angle angle_adjustment_set = np.arange(needle_angle-5.0,needle_angle+5.0,0.1) sum_pixels = [] for adj_angle in angle_adjustment_set: gauge.update_needle(adj_angle) gauge.get_needle((circle_x, circle_y-10)) overlap = cv2.bitwise_and(thresholded, gauge.needle_canvas) sum_pixels.append(np.sum(overlap/255)) adjustment_index = sum_pixels.index(max(sum_pixels)) needle_angle = angle_adjustment_set[adjustment_index] gauge.update_needle(needle_angle) gauge.get_needle((circle_x, circle_y-10)) needle_rgb = cv2.cvtColor(gauge.needle_canvas, cv2.COLOR_GRAY2BGR) canvas = cv2.add(canvas, needle_rgb/2) print "updated_guess: ", needle_angle pressure = np.interp(needle_angle, [DEF.GAUGE_MIN['angle'], DEF.GAUGE_MAX['angle']], [DEF.GAUGE_MIN['pressure'], DEF.GAUGE_MAX['pressure']]) pressure_str = str(round(pressure, 2)) print "pressure = ", pressure display_values(canvas, pressure_str) final_line_pt1 = (int(circle_x + radius * np.sin(geometry.degrees_to_radians(needle_angle))), int(circle_y - radius * np.cos(geometry.degrees_to_radians(needle_angle)))) final_line_pt2 = (int(circle_x + radius * np.sin(geometry.degrees_to_radians(needle_angle + 180))), int(circle_y - radius * np.cos(geometry.degrees_to_radians(needle_angle + 180)))) cv2.line(canvas, final_line_pt1, final_line_pt2, DEF.RED, thickness=DEF.THICKNESS*2) prep = cv2.bitwise_and(prep, mask) # plt.subplot(231) # plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB)) # plt.subplot(232) # plt.imshow(255 - mask_bandpass, 'gray') # plt.subplot(233) # plt.imshow(prep, 'gray') # plt.subplot(234) # plt.imshow(cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB)) # plt.subplot(235) # plt.plot(hist0) # plt.xlim([0, 256]) # plt.ylim([0, 50000]) # plt.show() cv2.circle(prep, (circle_x, circle_y), 25, (0, 255, 0), DEF.THICKNESS) prep = cv2.cvtColor(prep, cv2.COLOR_GRAY2BGR) canvas = np.concatenate((im, canvas), axis=1) host.write_to_file('w', "Pressure: " + pressure_str + " MPa", "Temperature: " + str(host.read_temp())) host.write_to_file('a', "circle_x:" + str(circle_x), "circle_y:" + str(circle_y), "radius:" + str(radius)) # pass in tuples ("filename.ext", img_to_write) image_path = re.sub('file', str(output_file), DEF.OUTPUT_PATH) host.write_image((image_path, canvas)) image_path = re.sub('file', str(output_file), DEF.THRESH_PATH) host.write_image((image_path, thresholded))
def make_box(self, site_edges): site = site_edges[0] edges = map(copy.deepcopy, site_edges[1]) def edge_intersects_box(edge): for box_edge in self.box_edges: if intersects(edge, box_edge): return True return False filtered_edges = filter(edge_intersects_box, edges) edge_collisions = {} for box_edge in self.box_edges: edge_collisions[box_edge] = [] for voronoi_edge in filtered_edges: if intersects(box_edge, voronoi_edge): edge_collisions[box_edge].append(voronoi_edge) unmatched_edges = [] for box_edge, collision_list in zip( edge_collisions.keys(), edge_collisions.values(), ): if len(collision_list) == 0: pass elif len(collision_list) == 1: unmatched_edges.append( (box_edge, collision_list[0]), ) else: new_start = intersection( collision_list[0], box_edge, ) new_end = intersection( collision_list[1], box_edge, ) new_edge = Edge(new_start, end_point=new_end) edges.append(new_edge) break if len(unmatched_edges) > 0: first_start = unmatched_edges[0][0].start_point first_end = unmatched_edges[0][0].end_point second_start = unmatched_edges[1][0].start_point second_end = unmatched_edges[1][0].end_point if first_start == second_start or first_start == second_end: common_corner = first_start elif first_end == second_start or first_end == second_end: common_corner = first_end else: raise ValueError("no common corner") first_intersection = intersection( unmatched_edges[0][0], unmatched_edges[0][1], ) first_new_edge = Edge( first_intersection, end_point=common_corner, ) second_intersection = intersection( unmatched_edges[1][0], unmatched_edges[1][1], ) second_new_edge = Edge( second_intersection, end_point=common_corner, ) edges.append(first_new_edge) edges.append(second_new_edge) return (site, edges)
def process_event(self, current_vertex): """ this function determine event type for current_vertex and maintain current edge list """ position = {} # end node is a selected node far away on sweep line end_up_node = Node(current_vertex.node.x, 1000) end_down_node = Node(current_vertex.node.x, -1000) sweepline = Edge(end_up_node, end_down_node) obstacle = vertex_in_obstacle(current_vertex, self.obstacle) for i in range(len(current_vertex.edge_list)): # position[edge]= left or right position[current_vertex.edge_list[i]] = left_or_right( current_vertex, current_vertex.edge_list[i]) # determine if upper or lower if current_vertex.edge_list[0].start != current_vertex.node: if current_vertex.edge_list[1].start != current_vertex.node: if current_vertex.edge_list[ 0].start.y > current_vertex.edge_list[1].start.y: E_upper = current_vertex.edge_list[0] E_lower = current_vertex.edge_list[1] else: E_upper = current_vertex.edge_list[1] E_lower = current_vertex.edge_list[0] else: if current_vertex.edge_list[ 0].start.y > current_vertex.edge_list[1].end.y: E_upper = current_vertex.edge_list[0] E_lower = current_vertex.edge_list[1] else: E_upper = current_vertex.edge_list[1] E_lower = current_vertex.edge_list[0] else: if current_vertex.edge_list[1].start != current_vertex.node: if current_vertex.edge_list[ 0].end.y > current_vertex.edge_list[1].start.y: E_upper = current_vertex.edge_list[0] E_lower = current_vertex.edge_list[1] else: E_upper = current_vertex.edge_list[1] E_lower = current_vertex.edge_list[0] else: if current_vertex.edge_list[ 0].end.y > current_vertex.edge_list[1].end.y: E_upper = current_vertex.edge_list[0] E_lower = current_vertex.edge_list[1] else: E_upper = current_vertex.edge_list[1] E_lower = current_vertex.edge_list[0] if position[E_upper][0] == "right" and position[E_lower][0] == "right": # insert E_upper and E_lower into current_edge self.current_edge_list.insert(E_upper, E_upper) self.current_edge_list.insert(E_lower, E_lower) prev = self.getPred(E_lower) succ = self.getSucc(E_upper) elif position[E_upper][0] == "right" and position[E_lower][0] == "left": # delete E_lower and insert E_upper prev = self.getPred(E_lower) self.current_edge_list.remove(E_lower) self.current_edge_list.insert(E_upper, E_upper) succ = self.getSucc(E_upper) elif position[E_upper][0] == "left" and position[E_lower][0] == "right": # delete E_upper and insert E_lower succ = self.getSucc(E_upper) self.current_edge_list.remove(E_upper) self.current_edge_list.insert(E_lower, E_lower) prev = self.getPred(E_lower) else: # delete E_upper and E_lower succ = self.getSucc(E_upper) prev = self.getPred(E_lower) self.current_edge_list.remove(E_upper) self.current_edge_list.remove(E_lower) if prev is not None: if not edge_in_polygon(prev, obstacle): inter1 = intersection(prev, sweepline) self.vertical_extension.append( Edge(current_vertex.node, inter1)) if succ is not None: if not edge_in_polygon(succ, obstacle): inter2 = intersection(succ, sweepline) self.vertical_extension.append( Edge(current_vertex.node, inter2))