Ejemplo n.º 1
0
def _md_preprocess_img(img, det_params):
    """Image preprocessing: grayscale conversion, edge filtering, and
    some minor denoising operations."""
    gray = imutils.grayscale(img)
    #TODO     #https://docs.opencv.org/3.4/d4/d73/tutorial_py_contours_begin.html    #findcontours should find (was???) White on black! - didn't look into it, but both b-on-w and w-on-b worked similarly well
    # Need to check why both thresh_bin and thresh_bin_inv works!
    _, bw = cv2.threshold(gray, 0.0, 255.0,
                          cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    wb = cv2.bitwise_not(bw)
    # Blur if needed
    if det_params.edge_blur_kernel_size > 0:
        bw = cv2.blur(bw.copy(), (det_params.edge_blur_kernel_size,
                                  det_params.edge_blur_kernel_size))
    # Edge detection
    edges = cv2.Canny(bw,
                      det_params.edge_canny_lower_thresh,
                      det_params.edge_canny_upper_thresh,
                      apertureSize=det_params.edge_sobel_aperture)
    # Close minor gaps via dilation
    if det_params.edge_dilation_kernel_size > 0:
        kernel = np.ones((det_params.edge_dilation_kernel_size,
                          det_params.edge_dilation_kernel_size), np.uint8)
        edges = cv2.dilate(edges, kernel, iterations=1)
    return PreprocessingResult(original=img,
                               gray=gray,
                               bw=bw,
                               wb=wb,
                               edges=edges)
Ejemplo n.º 2
0
def hough_lines(img):
    g = imutils.grayscale(img)
    vis = img.copy()
    edges = cv2.Canny(g, 100, 200, apertureSize=3)
    #lines = cv2.HoughLines(edges,1,np.pi/180,50)
    # for rho,theta in lines[0]:
    #     a = np.cos(theta)
    #     b = np.sin(theta)
    #     x0 = a*rho
    #     y0 = b*rho
    #     x1 = int(x0 + 1000*(-b))
    #     y1 = int(y0 + 1000*(a))
    #     x2 = int(x0 - 1000*(-b))
    #     y2 = int(y0 - 1000*(a))
    #     cv2.line(vis,(x1,y1),(x2,y2),(255,0,255),2)

    lines = cv2.HoughLinesP(edges,
                            1,
                            np.pi / 180,
                            20,
                            minLineLength=50,
                            maxLineGap=5)
    if lines is not None:
        for r in range(lines.shape[0]):
            # print(lines[r,:].shape, lines[r,:][0], lines[r,0,0], lines[r,:,:], lines[r,:])
            x1, y1, x2, y2 = lines[r, :][0]
            # for x1, y1, x2, y2 in lines:
            cv2.line(vis, (x1, y1), (x2, y2), (255, 0, 255), 2)
        #imvis.imshow(edges, title='edges', wait_ms=10)
    imvis.imshow(vis, title='Hough', wait_ms=10)
Ejemplo n.º 3
0
def fld_lines(img):
    #FIXME requires opencv-contrib-python
    g = imutils.grayscale(img)
    fld = cv2.ximgproc.createFastLineDetector()
    lines = fld.detect(g)
    vis = img.copy()
    vis = fld.drawSegments(vis, lines)
    imvis.imshow(vis, title='FLD lines', wait_ms=10)
Ejemplo n.º 4
0
def mser(img):
    g = imutils.grayscale(img)
    vis = img.copy()
    mser = cv2.MSER_create(_min_area=1000)
    regions, _ = mser.detectRegions(g)
    for p in regions:
        xmax, ymax = np.amax(p, axis=0)
        xmin, ymin = np.amin(p, axis=0)
        cv2.rectangle(vis, (xmin, ymax), (xmax, ymin), (0, 255, 0), 1)
    imvis.imshow(vis, title='mser', wait_ms=-1)
Ejemplo n.º 5
0
def contour(img):
    g = imutils.grayscale(img)
    _, g = cv2.threshold(g, 0.0, 255.0, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    # g = imutils.gaussian_blur(g, 1)
    # g = cv2.blur(g, (3,3))
    vis = imutils.ensure_c3(g)
    vis = img.copy()
    edges = cv2.Canny(g, 50, 200, apertureSize=3)
    kernel = np.ones((3, 3), np.uint8)
    edges = cv2.dilate(edges, kernel, iterations=1)
    cnts = cv2.findContours(edges, cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_NONE)  #cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    #https://docs.opencv.org/3.4/d4/d73/tutorial_py_contours_begin.html
    # White on black!

    approximated_polygons = list()
    for cnt in cnts:
        # get simplified convex hull
        epsilon = 0.05 * cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        hull = cv2.convexHull(approx)

        # cv2.drawContours(vis, [approx], 0, (0,255,0), 3)
        approximated_polygons.append({
            'hull': hull,
            'approx': approx,
            'hull_area': cv2.contourArea(hull),
            'corners': len(hull)
        })

    def _key(a):
        return a['hull_area']

    approximated_polygons.sort(key=_key, reverse=True)
    i = 0
    for approx in approximated_polygons:
        #cv2.drawContours(vis, [approx['cnt']], 0, (0,255,0) if i < 10 else (255,0,0), 3)
        cv2.drawContours(vis, [approx['hull']], 0,
                         (0, 255, 0) if 3 < approx['corners'] < 6 else
                         (255, 0, 0), 3)
        i += 1
        # if i < 15:
        # print('Largest', i, approx['approx'], approx['area'])
        # imvis.imshow(vis, title='contours', wait_ms=-1)
    imvis.imshow(vis, title='contours', wait_ms=-1)
Ejemplo n.º 6
0
    def align(self, image, H0):
        self.H0 = H0
        if self.verbose:
            vis = self._warp_current_image(image, np.eye(3))
            imvis.imshow(vis, 'Initial Warp', wait_ms=10)


        curr_original_image = image.copy()
        working_image = imutils.grayscale(image)
        working_image = cv2.GaussianBlur(working_image, self.blur_kernel_size, 0)
        working_pyramid = img_utils.image_pyramid(working_image, self.num_pyramid_levels)

        H = np.eye(3, dtype=float)
        # Coarse-to-fine:
        for lvl in range(self.num_pyramid_levels):
            pyr_lvl = self.num_pyramid_levels - lvl - 1
            H = self._process_in_layer(H, working_pyramid[pyr_lvl],
                                       self.template_pyramid[pyr_lvl], pyr_lvl)

        warped = self._warp_current_image(curr_original_image, H)
        return H, warped
Ejemplo n.º 7
0
 def __init__(self, image, method=Method.ESM, num_pyramid_levels=4,
              blur_kernel_size=(5, 5), max_iterations=50,
              verbose=False, full_reference_image=None):
     # TODO if verbose is True, you must provide the full reference image, too!
     self.verbose = verbose
     self.full_reference_image = full_reference_image
     self.template_image = imutils.grayscale(image)
     self.height, self.width = image.shape[:2]
     self.H0 = None
     self.H_gt = None
     self.method = method
     self.max_iterations = max_iterations
     self.num_pyramid_levels = num_pyramid_levels
     self.blur_kernel_size = blur_kernel_size
     self.template_image = cv2.GaussianBlur(self.template_image, self.blur_kernel_size, 0)
     self.template_pyramid = img_utils.image_pyramid(self.template_image, self.num_pyramid_levels)      
     self.sl3_bases = _get_SL3_bases()
     self.Jg = _compute_Jg(self.sl3_bases)
     self.JwJg = None
     self.dxdys = None  # Stores precomputed gradients for each pyramid level
     self.Js = None
     self.Hs = None
     self._precompute()
Ejemplo n.º 8
0
    def _compute_calibration_template(self):
        """Precomputes the calibration template image and reference points."""
        # Render full template
        tpl_full = imutils.grayscale(
            self.render_image())  # The rendered PNG will have 3-channels
        tpl_h, tpl_w = tpl_full.shape[:2]

        # Compute center marker position relative to the full target
        relrect_marker_tight, _ = self._get_relative_marker_rect(0)
        marker_roi_tight = Rect(left=tpl_w * relrect_marker_tight.left,
                                top=tpl_h * relrect_marker_tight.top,
                                width=tpl_w * relrect_marker_tight.width,
                                height=tpl_h * relrect_marker_tight.height)
        # Compute the corresponding corners for homography estimation (full
        # image warping) and ensure that they are sorted in CCW order
        ref_pts_marker_absolute = sort_points_ccw([
            marker_roi_tight.top_left, marker_roi_tight.bottom_left,
            marker_roi_tight.bottom_right, marker_roi_tight.top_right
        ])

        # Crop the central marker (with some small margin) and resize
        # to the configured template size
        relrect_marker_padded, rmr_offset = \
            self._get_relative_marker_rect(self.template_marker_margin_mm)
        marker_roi_padded = Rect(left=tpl_w * relrect_marker_padded.left,
                                 top=tpl_h * relrect_marker_padded.top,
                                 width=tpl_w * relrect_marker_padded.width,
                                 height=tpl_h * relrect_marker_padded.height)
        tpl_marker = cv2.resize(imutils.crop(tpl_full,
                                             marker_roi_padded.int_repr()),
                                dsize=(self.template_marker_size_px,
                                       self.template_marker_size_px),
                                interpolation=cv2.INTER_CUBIC)
        # Compute the reference corners for homography estimation and ensure that
        # they are sorted in CCW order
        ref_pts_tpl_marker = sort_points_ccw([
            Point(x=rmr_offset.x * tpl_marker.shape[1],
                  y=rmr_offset.y * tpl_marker.shape[0]),
            Point(x=tpl_marker.shape[1] - rmr_offset.x * tpl_marker.shape[1],
                  y=rmr_offset.y * tpl_marker.shape[0]),
            Point(x=tpl_marker.shape[1] - rmr_offset.x * tpl_marker.shape[1],
                  y=tpl_marker.shape[0] - rmr_offset.y * tpl_marker.shape[0]),
            Point(x=rmr_offset.x * tpl_marker.shape[1],
                  y=tpl_marker.shape[0] - rmr_offset.y * tpl_marker.shape[0])
        ])

        # Compute the circle template to locate the actual calibration reference
        # points (i.e. the grid points)
        relrect_circle, ref_pts_circle_relative = self._get_relative_marker_circle_v2(
        )
        circle_roi = Rect(left=tpl_w * relrect_circle.left,
                          top=tpl_h * relrect_circle.top,
                          width=tpl_w * relrect_circle.width,
                          height=tpl_h * relrect_circle.height)
        # Ensure the ROI is even (simplifies using the correlation results later on)
        circle_roi.ensure_odd_size()
        tpl_circle = imutils.crop(tpl_full, circle_roi.int_repr())
        ref_pts_tpl_circle = [
            Point(x=pt.x * tpl_circle.shape[1], y=pt.y * tpl_circle.shape[0])
            for pt in ref_pts_circle_relative
        ]
        # Compute expected size of a circle in the image template
        dia_circle_px = self.dia_circles_mm / self.target_width_mm * tpl_full.shape[
            1]
        ###DEBUG VISUALS
        # vis_tpl_circle = tpl_circle.copy()
        # foo = imutils.ensure_c3(tpl_full.copy()) # FIXME REMOVE
        # cv2.rectangle(foo, circle_roi.int_repr(), color=(0, 250, 0), thickness=3)
        # for pt in ref_pts_tpl_circle:
        #     cv2.circle(vis_tpl_circle, tuple(pt.int_repr()), radius=3, color=(200, 0, 0), thickness=1)
        # imvis.imshow(foo, 'FOO', wait_ms=10)
        # print(tpl_circle.shape, ref_pts_tpl_circle[0])
        # imvis.imshow(vis_tpl_circle, "CIRCLE????", wait_ms=-1)

        object.__setattr__(
            self,
            'calibration_template',
            CalibrationTemplate(
                tpl_full=tpl_full,
                refpts_full_marker=ref_pts_marker_absolute,
                #TODO extract reference points!!!! grid
                tpl_cropped_marker=tpl_marker,
                refpts_cropped_marker=ref_pts_tpl_marker,
                tpl_cropped_circle=tpl_circle,
                refpts_cropped_circle=ref_pts_tpl_circle,
                dia_circle_px=dia_circle_px))