Ejemplo n.º 1
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            # Determine the bounding rectangle of all contours
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
            image_height, image_width = image.shape[0], image.shape[1]

            # subtract the offset to move the bottom-left of the contour to [0,0]
            cnt_3d = [
                np.subtract(c, [x, y, 0], dtype=np.int32) for c in cnt_3d
            ]

            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            preview_cnt = contour_into_image(to_2D_contour(cnt_3d),
                                             preview_image)

            x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))

            # draw the coordinate axes
            # x-axis
            cv2.line(preview_image, (x, y + h), (x + w, y + h), (255, 0, 0), 1)
            # y-axis
            cv2.line(preview_image, (x, y), (x, y + h), (0, 0, 255), 1)

            # draw the contour itself
            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)
            image = preview_image

        return image, cnt_3d
Ejemplo n.º 2
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            # Determine the bounding rectangle of all contours
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
            image_height, image_width = image.shape[0], image.shape[1]

            # the offset to move the center of the contour to [0,0]
            offset_x = int(w / 2 + x)
            offset_y = int(h / 2 + y)

            cnt_3d = [np.subtract(c, [offset_x, offset_y, 0], dtype=np.int32) for c in cnt_3d]

            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)
            # generate a preview contour
            #
            preview_cnt = contour_into_image(to_2D_contour(cnt_3d), preview_image)

            # draw the coordinate system of the centered drawing contour
            x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))
            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)
            # horizontal
            cv2.line(preview_image, (x + int(w / 2), y + int(h / 2)), (x + w, y + int(h / 2)), (255, 0, 0), 1)
            # vertical
            cv2.line(preview_image, (x + int(w / 2), y), (x + int(w / 2), y + int(h / 2)), (0, 0, 255), 1)

            image = preview_image

        return image, cnt_3d
Ejemplo n.º 3
0
    def processed(self, image, cnt):
        self.cnt3D = cnt
        if len(cnt) == 0:
            return

        #  flip them upside down (gcode coordinate system vs. openCV coordinate system)
        cnt2D = to_2D_contour(cnt)
        x, y, w, h = cv2.boundingRect(np.concatenate(cnt2D))
        transform_y = lambda y_coord: (-(y_coord - y) + (y + h))
        cnt = ([
            np.array([[p[0], transform_y(p[1]), p[2]] for p in c]) for c in cnt
        ])

        itm_cnt = len(self.glWidget.items)
        idx = itm_cnt - 1
        while idx >= 0:
            if type(self.glWidget.items[idx]) == gl.GLLinePlotItem:
                del self.glWidget.items[idx]
            idx -= 1

        feed_rate = self.filter.feed_rate
        clearance = self.filter.clearance
        # Travel Toolpaths
        first_up = [0, 0, clearance]
        first_down = [0, 0, 0]

        plt = gl.GLLinePlotItem(pos=np.array([[0, 0, 0], [50, 0, 0]]),
                                width=4,
                                antialias=True,
                                color="0000ff")
        self.glWidget.addItem(plt)

        plt = gl.GLLinePlotItem(pos=np.array([[0, 0, 0], [0, 50, 0]]),
                                width=4,
                                antialias=True,
                                color="FF0000")
        self.glWidget.addItem(plt)

        # Carving Toolpaths
        for c in cnt:
            c = c / 1000
            plt = gl.GLLinePlotItem(pos=c,
                                    width=2,
                                    antialias=True,
                                    color="ECB151")
            self.glWidget.addItem(plt)

            # Tool Movement to start
            next_down = c[:1][0].tolist()  # first element
            next_up = [next_down[0], next_down[1], clearance]  # first element
            path = np.array([first_down, first_up, next_up, next_down])
            plt = gl.GLLinePlotItem(pos=path,
                                    width=1,
                                    antialias=True,
                                    color="3f3f3f3A")
            self.glWidget.addItem(plt)

            first_down = c[-1:][0].tolist()
            first_up = [first_down[0], first_down[1], clearance]
Ejemplo n.º 4
0
    def _process(self, image, cnt):
        try:
            single_channel = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

            generated_cnt = []

            row_index = 0  # [micro m]
            normalized_depth = self.depth_in_micro_m / 255
            for row in single_channel:
                rle_row = [rle for rle in self.rle(row) if rle[0] < 250]
                last_end = None
                last_contour = None
                for rle in rle_row:
                    # gray => depth in [micro m]
                    # 255  => 0 [micro m]                     # white means no cutting
                    #   0  => self.depth_in_micro_m [micro m] # black is full depth
                    depth = -(self.depth_in_micro_m - (normalized_depth * rle[0]))
                    gray_start = rle[1]
                    gray_end = rle[2] + gray_start
                    if gray_start == last_end:
                        last_contour = last_contour+[
                            [gray_start, row_index, depth],
                            [gray_end,   row_index, depth]
                        ]
                    else:
                        if not last_contour is None:
                            generated_cnt.append(np.array(last_contour,  dtype=np.int32))
                        last_contour = [
                            [gray_start, row_index, depth],
                            [gray_end,   row_index, depth]
                        ]
                    last_end = gray_end
                if not last_contour is None:
                    generated_cnt.append(np.array(last_contour,  dtype=np.int32))
                row_index += 1

            # generate a preview image
            #
            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            # generate a preview contour
            #
            preview_cnt = contour_into_image(to_2D_contour(generated_cnt), preview_image)

            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)
            # draw the carving depth
            cv2.putText(preview_image, "Carving Depth {:.2f} mm".format(self.depth_in_micro_m / 1000), (20, 50),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 4)

            image = preview_image

            return image, generated_cnt
        except Exception as exc:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print(type(self), exc)
Ejemplo n.º 5
0
    def _process(self, image, cnt_3d):
        try:
            if len(cnt_3d) > 0:
                cnt = to_2D_contour(cnt_3d)
                x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
                image_height, image_width = image.shape[0], image.shape[1]

                # the offset to move the center of the contour to [0,0]
                cx = int(w / 2 + x)
                cy = int(h / 2 + y)

                a = math.radians(self.angle_in_degree)
                ca = math.cos(a)
                sa = math.sin(a)

                rotate_point = lambda p: [
                    int(((p[0] - cx) * ca) - ((p[1] - cy) * sa) + cx),
                    int(((p[0] - cx) * sa) + ((p[1] - cy) * ca) + cy),
                    p[2]
                ]
                rotate_cnt = lambda c: np.array([rotate_point(p) for p in c])
                cnt_3d = [rotate_cnt(c) for c in cnt_3d]

                preview_image = np.zeros(image.shape, dtype="uint8")
                preview_image.fill(255)
                # generate a preview contour
                #
                preview_cnt = contour_into_image(to_2D_contour(cnt_3d), preview_image)

                # draw the coordinate system of the centered drawing contour
                x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))
                cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)
                # horizontal
                cv2.line(preview_image, (x + int(w / 2), y + int(h / 2)), (x + w, y + int(h / 2)), (255, 0, 0), 1)
                # vertical
                cv2.line(preview_image, (x + int(w / 2), y), (x + int(w / 2), y + int(h / 2)), (0, 0, 255), 1)

                image = newimage
        except Exception as exc:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print(type(self), exc)

        return image, cnt_3d
Ejemplo n.º 6
0
    def gcode(self, cnt_3d):
        cnt = to_2D_contour(cnt_3d)

        clearance = self.conf_file.get_float(key="clearance",
                                             section=self.conf_section)
        feed_rate = self.conf_file.get_float(key="feed_rate",
                                             section=self.conf_section)

        code = GCode()
        code.feed_rate = feed_rate
        code.rapid_rate = feed_rate * 2
        code.clearance = clearance

        if cnt_3d and len(cnt_3d) > 0:
            # Determine the bounding rectangle

            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))

            # scale contour from [micro m] to [mm]
            scale_factor = 0.001

            # transform all coordinates and generate gcode
            # for this we must apply:
            #    - the scale factor
            #    - flip them upside down (gcode coordinate system vs. openCV coordinate system)
            #
            transform_y = lambda y_coord: (-(y_coord - y) + (y + h))

            code.raise_mill()
            code.feed_rapid({"x": 0, "y": 0})
            code.start_spindle()
            for c in cnt_3d:
                i = 0
                while i < len(c):
                    p = c[i]
                    grbl_x = '{:06.4f}'.format(p[0] * scale_factor)
                    grbl_y = '{:06.4f}'.format(
                        (transform_y(p[1])) * scale_factor)
                    grbl_z = '{:06.4f}'.format(p[2] * scale_factor)
                    position_save = {"x": grbl_x, "y": grbl_y}
                    position_carving = {"x": grbl_x, "y": grbl_y, "z": grbl_z}
                    if i == 0:
                        code.feed_rapid(position_save)
                        # move close to the surface
                        code.drop_mill()
                        # carve slowly into the workpiece until the bit has reached the final depth
                        code.feed_linear({"z": grbl_z})
                    else:
                        # move to the new x/y/z coordinate
                        code.feed_linear(position_carving)
                    i += 1
                code.feed_linear({"z": 0})
                code.raise_mill()
            code.stop_spindle()
            code.feed_rapid({"x": 0, "y": 0})

        return code
Ejemplo n.º 7
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            # Determine the bounding rectangle of all contours
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
            image_height, image_width = image.shape[0], image.shape[1]

            shift_x = int((x + (w / 2)) - image_width / 2)
            shift_y = int((y + (h / 2)) - image_height / 2)
            cnt_3d = [
                np.subtract(c, [shift_x, shift_y, 0], dtype=np.int32)
                for c in cnt_3d
            ]

            cnt = to_2D_contour(cnt_3d)
            newimage = np.zeros(image.shape, dtype="uint8")
            newimage.fill(255)
            cv2.drawContours(newimage, cnt, -1, (60, 169, 242), 1)
            image = newimage

        return image, cnt_3d
Ejemplo n.º 8
0
    def process(self, image, cnt_3d):
       if len(cnt_3d)>0:
            cnt = to_2D_contour(cnt_3d)
            # Determine the bounding rectangle of all contours
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
            image_height, image_width = image.shape[0], image.shape[1]

            # the offset to move the center of the contour to [0,0]
            offset_x = x
            offset_y = y

            newimage = np.zeros(image.shape, dtype="uint8")
            newimage.fill(255)

            cnt_3d = [np.subtract(c, [offset_x, offset_y, 0], dtype=np.int32) for c in cnt_3d]

            drawing_cnt = to_2D_contour(cnt_3d)
            w2=image_width/2
            h2=image_height/2
            for c in drawing_cnt:
                i = 0
                while i < len(c):
                    p = c[i]
                    p[0] = p[0] + w2 - w/2
                    p[1] = p[1] + h2 - h/2
                    i+=1

            x, y, w, h = cv2.boundingRect(np.concatenate(drawing_cnt))

            # draw the width dimension
            # horizontal
            cv2.line(newimage, (x,y+h),(x+w,y+h), (255, 0, 0), 1)
            # vertical
            cv2.line(newimage, (x,y),(x,y+h), (0, 0, 255), 1)

            cv2.drawContours(newimage, drawing_cnt, -1,  (60,169,242), 1)
            image = newimage

       return image, cnt_3d
Ejemplo n.º 9
0
    def process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            for c in cnt_3d:
                for p in c:
                    p[2] = -self.depth_in_micro_m

            cnt = to_2D_contour(cnt_3d)

            newimage = np.zeros(image.shape, dtype="uint8")
            newimage.fill(255)

            # create a new cnt for the drawing on the image. The cnt should cover 4/5 of the overal image
            #
            image_height, image_width = image.shape[0], image.shape[1]
            drawing_cnt = copy.deepcopy(cnt)
            x, y, w, h = cv2.boundingRect(np.concatenate(drawing_cnt))
            drawing_factor_w = (image_width / w) * 0.8
            drawing_factor_h = (image_height / h) * 0.8
            # ensure that the drawing fits into the preview image
            drawing_factor = drawing_factor_w if drawing_factor_w < drawing_factor_h else drawing_factor_h
            offset_x = (w / 2 + x) * drawing_factor
            offset_y = (h / 2 + y) * drawing_factor
            for c in drawing_cnt:
                i = 0
                while i < len(c):
                    p = c[i]
                    p[0] = (p[0] * drawing_factor) + (image_width /
                                                      2) - offset_x
                    p[1] = (p[1] * drawing_factor) + (image_height /
                                                      2) - offset_y
                    i += 1

            cv2.drawContours(newimage, drawing_cnt, -1, (60, 169, 242), 1)
            cv2.rectangle(newimage, (x, y), (x + w, y + h), (0, 255, 0), 1)

            # draw the carving depth
            cv2.putText(
                newimage,
                "Carving Depth {:.2f} mm".format(self.depth_in_micro_m / 1000),
                (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 4)

            image = newimage

        return image, cnt_3d
Ejemplo n.º 10
0
    def process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            # Determine the bounding rectangle of all contours
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))
            image_height, image_width = image.shape[0], image.shape[1]

            # the offset to move the center of the contour to [0,0]
            offset_x = int(w / 2 + x)
            offset_y = int(h / 2 + y)

            cnt_3d = [
                np.subtract(c, [offset_x, offset_y, 0], dtype=np.int32)
                for c in cnt_3d
            ]

            # shift the contour to the center. Only required for the drawing
            #
            w2 = int(image_width / 2) - offset_x
            h2 = int(image_height / 2) - offset_y
            drawing_cnt = [
                np.subtract(c, [-w2, -h2], dtype=np.int32) for c in cnt
            ]
            newimage = np.zeros(image.shape, dtype="uint8")
            newimage.fill(255)

            # draw the coordinate system of the centered drawing contour
            x, y, w, h = cv2.boundingRect(np.concatenate(drawing_cnt))
            cv2.drawContours(newimage, drawing_cnt, -1, (60, 169, 242), 1)
            # horizontal
            cv2.line(newimage, (x + int(w / 2), y + int(h / 2)),
                     (x + w, y + int(h / 2)), (255, 0, 0), 1)
            # vertical
            cv2.line(newimage, (x + int(w / 2), y),
                     (x + int(w / 2), y + int(h / 2)), (0, 0, 255), 1)

            image = newimage

        return image, cnt_3d
Ejemplo n.º 11
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            for c in cnt_3d:
                for p in c:
                    p[2] = -self.depth_in_micro_m

            cnt = to_2D_contour(cnt_3d)

            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            # create a new cnt for the drawing on the image. The cnt should cover 4/5 of the overall image
            preview_cnt = contour_into_image(cnt, preview_image)
            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)

            # draw the carving depth
            cv2.putText(
                preview_image,
                "Carving Depth {:.2f} mm".format(self.depth_in_micro_m / 1000),
                (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 4)

            image = preview_image

        return image, cnt_3d
Ejemplo n.º 12
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:

            def gauss_kernel(kernlen=21, nsig=3):
                x = np.linspace(-nsig, nsig, kernlen)
                kern1d = np.diff(st.norm.cdf(x))
                return kern1d / kern1d.sum()

            # repeat and insert the first and last value in the array n-times
            # (expand the array at the beginning and end). Required for convolve function.
            #
            add_padding = lambda array, n: np.insert(
                np.insert(array, 0, np.full(n, array[0])), -1,
                np.full(n, array[-1]))

            box = gauss_kernel(self.window)
            padding = int(self.window / 2)
            smoothed_cnt = []

            for c in cnt_3d:
                x, y, z = c.T
                if len(z) > 0:
                    if len(z) > self.window:
                        x_new = np.convolve(add_padding(x, padding),
                                            box,
                                            mode="valid")
                        y_new = np.convolve(add_padding(y, padding),
                                            box,
                                            mode="valid")
                        z_new = np.convolve(add_padding(z, padding),
                                            box,
                                            mode="valid")
                        # replace the starting points and end points of the CNC contour with the original points.
                        # We don't want modify the start / end of an contour. The reason for that is, that this is normaly
                        # cut-into movement into the stock without any tolerances. So - don't modify them.
                        #
                        # Replace the START Points with the original one
                        x_new[0:padding] = x[0:padding]
                        y_new[0:padding] = y[0:padding]
                        z_new[0:padding] = z[0:padding]
                        # Replace the END Points with the original one
                        x_new[-padding:] = x[-padding:]
                        y_new[-padding:] = y[-padding:]
                        z_new[-padding:] = z[-padding:]

                        smoothed_cnt.append(
                            np.asarray([[int(i[0]),
                                         int(i[1]),
                                         int(i[2])]
                                        for i in zip(x_new, y_new, z_new)]))
                    else:
                        smoothed_cnt.append(c)

            # generate a preview image
            #
            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            # generate a preview contour
            #
            preview_cnt = contour_into_image(to_2D_contour(smoothed_cnt),
                                             preview_image)

            # draw the centered contour
            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)

            image = preview_image
            cnt_3d = smoothed_cnt

        return image, cnt_3d
Ejemplo n.º 13
0
    def process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            display_factor = 0.001 if self.display_unit == "mm" else 0.0001

            # Determine the origin bounding rectangle
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))

            # Ensure that width of the contour is the same as the width_in_mm.
            # Scale the contour to the required width.
            scaled_factor = self.width_in_micro_m / w
            scaled_cnt = [
                np.multiply(c.astype(np.float),
                            [scaled_factor, scaled_factor, 1]).astype(np.int32)
                for c in cnt_3d
            ]

            # create a new cnt for the drawing on the image. The cnt should cover 4/5 of the overall image
            #
            height_in_micro_m = self.width_in_micro_m / w * h
            image_height, image_width = image.shape[0], image.shape[1]
            drawing_factor_w = (image_width / w) * 0.8
            drawing_factor_h = (image_height / h) * 0.8
            # ensure that the drawing fits into the preview image
            drawing_factor = drawing_factor_w if drawing_factor_w < drawing_factor_h else drawing_factor_h
            offset_x = (image_width / 2) - (w / 2 + x) * drawing_factor
            offset_y = (image_height / 2) - (h / 2 + y) * drawing_factor
            drawing_cnt = [
                np.add(
                    np.multiply(c.astype(np.float),
                                [drawing_factor, drawing_factor]),
                    [offset_x, offset_y]).astype(np.int32) for c in cnt
            ]

            # generate a preview image
            #
            newimage = np.zeros(image.shape, dtype="uint8")
            newimage.fill(255)

            # determine the drawing bounding box
            x, y, w, h = cv2.boundingRect(np.concatenate(drawing_cnt))

            # draw the centered contour
            cv2.drawContours(newimage, drawing_cnt, -1, (60, 169, 242), 1)
            cv2.rectangle(newimage, (x, y), (x + w, y + h), (0, 255, 0), 2)

            # draw the width dimension
            cv2.line(newimage, (x, y + int(h / 2)), (x + w, y + int(h / 2)),
                     (255, 0, 0), 2)
            cv2.circle(newimage, (x, y + int(h / 2)), 15, (255, 0, 0), -1)
            cv2.circle(newimage, (x + w, y + int(h / 2)), 15, (255, 0, 0), -1)
            cv2.putText(
                newimage,
                "{:.1f} {}".format(self.width_in_micro_m * display_factor,
                                   self.display_unit),
                (x + 20, y + int(h / 2) - 30), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            # draw the height dimension
            cv2.line(newimage, (x + int(w / 2), y), (x + int(w / 2), y + h),
                     (255, 0, 0), 2)
            cv2.circle(newimage, (x + int(w / 2), y), 15, (255, 0, 0), -1)
            cv2.circle(newimage, (x + int(w / 2), y + h), 15, (255, 0, 0), -1)
            cv2.putText(
                newimage,
                "{:.1f} {}".format(height_in_micro_m * display_factor,
                                   self.display_unit),
                (x + int(w / 2) + 20, y + 50), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            image = newimage
            cnt_3d = scaled_cnt

        return image, cnt_3d
Ejemplo n.º 14
0
    def _process(self, image, cnt):

        try:
            PADDING = 2
            # add padding to the image to avoid that we run out of index in the np.amax calculation
            image = cv2.copyMakeBorder(image, PADDING, PADDING, PADDING,
                                       PADDING, cv2.BORDER_CONSTANT, None,
                                       [255, 255, 255])

            image_height, image_width = image.shape[0], image.shape[1]

            # generate the skeleton of the "BLACK" area and returns an image in which the
            # "white" part is the skeleton.
            #
            image_skeleton = image.copy(
            )  # deepcopy to protect the original image
            image_skeleton = cv2.threshold(image_skeleton, 127, 255,
                                           cv2.THRESH_BINARY_INV)[1]
            image_skeleton, _, _ = cv2.split(image_skeleton)
            #image_skeleton = 255 - cv2.ximgproc.thinning(image_skeleton, cv2.ximgproc.THINNING_GUOHALL)
            image_skeleton = cv2.ximgproc.thinning(
                image_skeleton, cv2.ximgproc.THINNING_ZHANGSUEN)

            # calculate the watershed distance. This is a distance calculation of the original image
            #
            image_watershed = 255 - cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            image_watershed = cv2.distanceTransform(image_watershed,
                                                    cv2.DIST_L2, 5)
            image_watershed = cv2.convertScaleAbs(image_watershed)
            image_watershed = cv2.normalize(image_watershed, None, 255, 0,
                                            cv2.NORM_MINMAX, cv2.CV_8UC1)

            # calculate the mask and use just the pixel and the intensity for the carving depth
            # now we have just the skeleton image with the distance information (carving depth)
            image_carvingpath = cv2.bitwise_and(image_watershed,
                                                image_skeleton)

            # CHAIN_APPROX_NONE is important to get each and every pixel in the contour and not the reduced one.
            #
            cnt, hierarchy = cv2.findContours(image_skeleton, cv2.RETR_TREE,
                                              cv2.CHAIN_APPROX_NONE)
            cnt = normalize_contour(cnt)
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))

            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            generated_cnt = ensure_3D_contour(cnt)
            dots_in_width = int(self.width_in_micro_m /
                                min(self.cutter_bit_diameter_in_micro_m,
                                    self.max_diameter_in_micro_m))
            max_diameter_in_pixel = (image_width / dots_in_width)
            carving_depth = lambda gray: -(
                self.max_diameter_in_micro_m / 255 * (gray)) / (math.tan(
                    math.radians(self.cutter_bit_angle / 2)) * 2)
            circle_radius = lambda gray: int(((max_diameter_in_pixel / 255) *
                                              (gray)) / 2)
            for c in generated_cnt:
                i = 0
                while i < len(c):
                    p = c[i]
                    row = p[1]
                    col = p[0]
                    neighbours = image_carvingpath[row - 2:row + 2,
                                                   col - 2:col + 2]
                    max = np.amax(neighbours)
                    p[2] = carving_depth(max)
                    cv2.circle(preview_image, (col, row), circle_radius(max),
                               (60, 169, 242), -1)
                    i = i + 1

            cv2.drawContours(preview_image, to_2D_contour(generated_cnt), -1,
                             (0, 49, 252), 1)

            display_factor = 0.001 if self.display_unit == "mm" else 0.0001

            # draw the width dimension
            cv2.line(preview_image, (x, y + int(h / 2)),
                     (x + w, y + int(h / 2)), (255, 0, 0), 1)
            cv2.circle(preview_image, (x, y + int(h / 2)), 5, (255, 0, 0), -1)
            cv2.circle(preview_image, (x + w, y + int(h / 2)), 5, (255, 0, 0),
                       -1)
            cv2.putText(
                preview_image,
                "{:.1f} {}".format(self.width_in_micro_m * display_factor,
                                   self.display_unit),
                (x + 20, y + int(h / 2) - 30), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            # draw the height dimension
            height_in_micro_m = self.width_in_micro_m / w * h
            cv2.line(preview_image, (x + int(w / 2), y),
                     (x + int(w / 2), y + h), (255, 0, 0), 1)
            cv2.circle(preview_image, (x + int(w / 2), y), 5, (255, 0, 0), -1)
            cv2.circle(preview_image, (x + int(w / 2), y + h), 5, (255, 0, 0),
                       -1)
            cv2.putText(
                preview_image,
                "{:.1f} {}".format(height_in_micro_m * display_factor,
                                   self.display_unit),
                (x + int(w / 2) + 20, y + 50), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            # Ensure that width of the contour is the same as the width_in_mm.
            # Scale the contour to the required width.
            scale_factor = self.width_in_micro_m / w
            generated_cnt = [
                np.multiply(c.astype(np.float),
                            [scale_factor, scale_factor, 1]).astype(np.int32)
                for c in generated_cnt
            ]
            preview_image = preview_image[PADDING:-PADDING, PADDING:-PADDING]
            return preview_image, generated_cnt
        except Exception as exc:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print(type(self), exc)
Ejemplo n.º 15
0
    def _process(self, image, cnt_3d):
        if len(cnt_3d) > 0:
            cnt = to_2D_contour(cnt_3d)
            display_factor = 0.001 if self.display_unit == "mm" else 0.0001

            # Determine the origin bounding rectangle
            x, y, w, h = cv2.boundingRect(np.concatenate(cnt))

            # Ensure that width of the contour is the same as the width_in_mm.
            # Scale the contour to the required width.
            scaled_factor = self.width_in_micro_m / w
            scaled_cnt = [
                np.multiply(c.astype(np.float),
                            [scaled_factor, scaled_factor, 1]).astype(np.int32)
                for c in cnt_3d
            ]

            # generate a preview image
            #
            preview_image = np.zeros(image.shape, dtype="uint8")
            preview_image.fill(255)

            # generate a preview contour
            #
            preview_cnt = contour_into_image(to_2D_contour(scaled_cnt),
                                             preview_image)

            # determine the drawing bounding box
            x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))

            # draw the centered contour
            cv2.drawContours(preview_image, preview_cnt, -1, (60, 169, 242), 1)

            # draw the width dimension
            cv2.line(preview_image, (x, y + int(h / 2)),
                     (x + w, y + int(h / 2)), (255, 0, 0), 1)
            cv2.circle(preview_image, (x, y + int(h / 2)), 5, (255, 0, 0), -1)
            cv2.circle(preview_image, (x + w, y + int(h / 2)), 5, (255, 0, 0),
                       -1)
            cv2.putText(
                preview_image,
                "{:.1f} {}".format(self.width_in_micro_m * display_factor,
                                   self.display_unit),
                (x + 20, y + int(h / 2) - 30), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            # draw the height dimension
            height_in_micro_m = self.width_in_micro_m / w * h
            cv2.line(preview_image, (x + int(w / 2), y),
                     (x + int(w / 2), y + h), (255, 0, 0), 1)
            cv2.circle(preview_image, (x + int(w / 2), y), 5, (255, 0, 0), -1)
            cv2.circle(preview_image, (x + int(w / 2), y + h), 5, (255, 0, 0),
                       -1)
            cv2.putText(
                preview_image,
                "{:.1f} {}".format(height_in_micro_m * display_factor,
                                   self.display_unit),
                (x + int(w / 2) + 20, y + 50), cv2.FONT_HERSHEY_SIMPLEX, 1.65,
                (255, 0, 0), 4)

            image = preview_image
            cnt_3d = scaled_cnt

        return image, cnt_3d