Exemple #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
Exemple #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
Exemple #3
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)
Exemple #4
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
Exemple #5
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
Exemple #6
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
Exemple #7
0
    def _process(self, image, cnt):
        try:
            # generate an inverted, single channel image. Normally OpenCV detect on "white"....but we
            # want use "black" as contour foundation
            #
            single_channel = 255 - cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

            # determine the contour
            # https://docs.opencv.org/3.4.0/d9/d8b/tutorial_py_contours_hierarchy.html
            # We need the "two level" of hierarchy for the contour to perform clipping.
            # The hierarchy is stored in that pattern: [Next, Previous, First_Child, Parent]
            #
            cnt, hierarchy = cv2.findContours(single_channel, cv2.RETR_CCOMP,
                                              cv2.CHAIN_APPROX_NONE)
            hierarchy = hierarchy[0]
            print(hierarchy)
            validated_cnt = normalize_contour(cnt)

            # scale the contour to the user defined width if we have any
            #
            if len(validated_cnt) > 0:
                # Determine the bounding rectangle
                x, y, w, h = cv2.boundingRect(np.concatenate(validated_cnt))

                # 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
                scaled_cnt = [
                    np.multiply(c.astype(np.float),
                                [scale_factor, scale_factor]).astype(np.int32)
                    for c in validated_cnt
                ]

                # generate a hatch pattern we want to apply
                pattern = self.build_hatch_pattern(scaled_cnt)

                hatch_cnt = []
                for parent_i in range(len(hierarchy)):
                    # [Next, Previous, First_Child, Parent]
                    # Process the parents only. It is a Parent if  "Parent" is "-1".
                    parent_h = hierarchy[parent_i]
                    if parent_h[3] == -1:
                        clip_cnt = [scaled_cnt[parent_i].tolist()]
                        # append all child contours of the parent
                        for child_i in range(len(hierarchy)):
                            child_h = hierarchy[child_i]
                            if child_h[3] == parent_i:
                                clip_cnt.append(scaled_cnt[child_i].tolist())
                        # clip the hatch with the calculated "clipping region"
                        #
                        try:
                            pc = pyclipper.Pyclipper()
                            pc.AddPaths(clip_cnt, pyclipper.PT_CLIP, True)
                            pc.AddPaths(pattern, pyclipper.PT_SUBJECT, False)
                            solution = pc.Execute2(pyclipper.CT_INTERSECTION,
                                                   pyclipper.PFT_EVENODD,
                                                   pyclipper.PFT_EVENODD)
                            # add the clipped hatch to the overall contour result
                            hatch = pyclipper.PolyTreeToPaths(solution)
                            for c in hatch:
                                hatch_cnt.append(np.array(c))
                        except:
                            pass
                # h_cnt = scaled_cnt.copy()
                scaled_cnt = hatch_cnt + scaled_cnt

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

                # draw some debug information
                #i = 0
                #h_cnt = contour_into_image(h_cnt, preview_image)
                #for c in h_cnt:
                #    cv2.putText(preview_image, str(i), (c[0][0], c[0][1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
                #    i = i + 1

                # place the contour into the center of the image
                preview_cnt = contour_into_image(scaled_cnt, preview_image)
                x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))

                # draw the outline contour in yellow
                cv2.drawContours(preview_image, preview_cnt, -1,
                                 (60, 169, 242), 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)

                image = preview_image
                validated_cnt = scaled_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)

        return image, validated_cnt
Exemple #8
0
    def _process(self, image, cnt):
        try:
            # generate an inverted, single channel image. Normally OpenCV detect on "white"....but we
            # want use "black" as contour foundation
            #
            single_channel = 255 - cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

            # determine the contour
            #
            cnt, hierarchy = cv2.findContours(single_channel, cv2.RETR_TREE,
                                              cv2.CHAIN_APPROX_SIMPLE)
            i = 0
            validated_cnt = []
            while i < len(cnt):
                c = cnt[i]
                sq_cnt = np.squeeze(c)
                if len(sq_cnt.shape) == 2:
                    sq_cnt = np.append(sq_cnt, [[sq_cnt[0][0], sq_cnt[0][1]]],
                                       axis=0)
                    validated_cnt.append(sq_cnt)
                i += 1

            # scale the contour to the user defined width
            #
            if len(validated_cnt) > 0:
                # Determine the origin bounding rectangle
                x, y, w, h = cv2.boundingRect(np.concatenate(validated_cnt))

                # 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
                scaled_cnt = [
                    np.multiply(c.astype(np.float),
                                [scale_factor, scale_factor]).astype(np.int32)
                    for c in validated_cnt
                ]

                # 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(scaled_cnt, preview_image)
                x, y, w, h = cv2.boundingRect(np.concatenate(preview_cnt))

                # draw the preview contour
                cv2.drawContours(preview_image, preview_cnt, -1,
                                 (60, 169, 242), 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)

                image = preview_image
                validated_cnt = scaled_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)

        return image, validated_cnt
Exemple #9
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