def check_image(fname, poller):
    """
    Check method that ensures the image is valid.

    :param fname: the file to check
    :type fname: str
    :param poller: the Poller instance that called the method
    :type poller: Poller
    :return: True if complete
    :rtype: bool
    """
    result = auto.is_image_complete(fname)
    poller.debug("Image complete:", fname, "->", result)
    return result
Exemple #2
0
def predict_on_images(input_dir, graph, sess, output_dir, tmp_dir, score_threshold, categories, num_imgs, inference_times,
                      delete_input, output_polygons, mask_threshold, mask_nth, output_minrect, view_margin, fully_connected,
                      fit_bbox_to_polygon, output_width_height, bbox_as_fallback):
    """
    Method performing predictions on all images ony by one or combined as specified by the int value of num_imgs.

    :param input_dir: the directory with the images
    :type input_dir: str
    :param graph: the graph to use
    :type graph: tf.Graph()
    :param sess: the tensorflow session
    :type sess: tf.Session
    :param output_dir: the output directory to move the images to and store the predictions
    :type output_dir: str
    :param tmp_dir: the temporary directory to store the predictions until finished
    :type tmp_dir: str
    :param score_threshold: the minimum score predictions have to have
    :type score_threshold: float
    :param categories: the label map
    :param num_imgs: the number of images to combine into one before presenting to graph
    :type num_imgs: int
    :param inference_times: whether to output a CSV file with the inference times
    :type inference_times: bool
    :param delete_input: whether to delete the input images rather than moving them to the output directory
    :type delete_input: bool
    :param output_polygons: whether the model predicts masks and polygons should be stored in the CSV files
    :type output_polygons: bool
    :param mask_threshold: the threshold to use for determining the contour of a mask
    :type mask_threshold: float
    :param mask_nth: to speed up polygon computation, use only every nth row and column from mask
    :type mask_nth: int
    :param output_minrect: when predicting polygons, whether to output the minimal rectangles around the objects as well
    :type output_minrect: bool
    :param view_margin: the margin in pixels to use around the masks
    :type view_margin: int
    :param fully_connected: whether regions of 'high' or 'low' values should be fully-connected at isthmuses
    :type fully_connected: str
    :param fit_bbox_to_polygon: whether to fit the bounding box to the polygon
    :type fit_bbox_to_polygon: bool
    :param output_width_height: whether to output x/y/w/h instead of x0/y0/x1/y1
    :type output_width_height: bool
    :param bbox_as_fallback: if ratio between polygon-bbox and bbox is smaller than this value, use bbox as fallback polygon, ignored if < 0
    :type bbox_as_fallback: float
    """

    # Iterate through all files present in "test_images_directory"
    total_time = 0
    if inference_times:
        times = list()
        times.append("Image(s)_file_name(s),Total_time(ms),Number_of_images,Time_per_image(ms)\n")

    # counter for keeping track of images that cannot be processed
    incomplete_counter = dict()

    while True:
        start_time = datetime.now()
        im_list = []
        # Loop to pick up images equal to num_imgs or the remaining images if less
        for image_path in os.listdir(input_dir):
            # Load images only
            ext_lower = os.path.splitext(image_path)[1]
            if ext_lower in SUPPORTED_EXTS:
                full_path = os.path.join(input_dir, image_path)
                if auto.is_image_complete(full_path):
                    im_list.append(full_path)
                else:
                    if not full_path in incomplete_counter:
                        incomplete_counter[full_path] = 1
                    else:
                        incomplete_counter[full_path] = incomplete_counter[full_path] + 1

            # remove images that cannot be processed
            remove_from_blacklist = []
            for k in incomplete_counter:
                if incomplete_counter[k] == MAX_INCOMPLETE:
                    print("%s - %s" % (str(datetime.now()), os.path.basename(k)))
                    remove_from_blacklist.append(k)
                    try:
                        if delete_input:
                            print("  flagged as incomplete {} times, deleting\n".format(MAX_INCOMPLETE))
                            os.remove(k)
                        else:
                            print("  flagged as incomplete {} times, skipping\n".format(MAX_INCOMPLETE))
                            os.rename(k, os.path.join(output_dir, os.path.basename(k)))
                    except:
                        print(traceback.format_exc())

            for k in remove_from_blacklist:
                del incomplete_counter[k]

            if len(im_list) == num_imgs:
                break

        if len(im_list) == 0:
            time.sleep(1)
            break
        else:
            print("%s - %s" % (str(datetime.now()), ", ".join(os.path.basename(x) for x in im_list)))

        try:
            # Combining picked up images
            i = len(im_list)
            combined = []
            comb_img = None
            if i > 1:
                while i != 0:
                    if comb_img is None:
                        img2 = Image.open(im_list[i-1])
                        img1 = Image.open(im_list[i-2])
                        i -= 1
                        combined.append(os.path.join(output_dir, "combined.png"))
                    else:
                        img2 = comb_img
                        img1 = Image.open(im_list[i-1])
                    i -= 1
                    # Remove alpha channel if present
                    img1 = remove_alpha_channel(img1)
                    img2 = remove_alpha_channel(img2)
                    w1, h1 = img1.size
                    w2, h2 = img2.size
                    comb_img = np.zeros((h1+h2, max(w1, w2), 3), np.uint8)
                    comb_img[:h1, :w1, :3] = img1
                    comb_img[h1:h1+h2, :w2, :3] = img2
                    comb_img = Image.fromarray(comb_img)

            if comb_img is None:
                im_name = im_list[0]
                image = Image.open(im_name)
                image = remove_alpha_channel(image)
            else:
                im_name = combined[0]
                image = remove_alpha_channel(comb_img)

            image_np = image_to_numpyarray(image)
            output_dict = inference_for_image(image_np, graph, sess)

            # Loading results
            boxes = output_dict['detection_boxes']
            scores = output_dict['detection_scores']
            classes = output_dict['detection_classes']

            # Code for splitting rois to multiple csv's, one csv per image before combining
            max_height = 0
            prev_min = 0
            for i in range(len(im_list)):
                img = Image.open(im_list[i])
                img_height = img.height
                min_height = prev_min
                max_height += img_height
                prev_min = max_height
                roi_path = "{}/{}-rois.csv".format(output_dir, os.path.splitext(os.path.basename(im_list[i]))[0])
                if tmp_dir is not None:
                    roi_path_tmp = "{}/{}-rois.tmp".format(tmp_dir, os.path.splitext(os.path.basename(im_list[i]))[0])
                else:
                    roi_path_tmp = "{}/{}-rois.tmp".format(output_dir, os.path.splitext(os.path.basename(im_list[i]))[0])

                roiobjs = []
                for index in range(output_dict['num_detections']):
                    score = scores[index]

                    # Ignore this roi if the score is less than the provided threshold
                    if score < score_threshold:
                        continue

                    y0n, x0n, y1n, x1n = boxes[index]

                    # Translate roi coordinates into combined image coordinates
                    x0 = x0n * image.width
                    y0 = y0n * image.height
                    x1 = x1n * image.width
                    y1 = y1n * image.height

                    if y0 > max_height or y1 > max_height:
                        continue
                    elif y0 < min_height or y1 < min_height:
                        continue

                    label = classes[index]
                    label_str = categories[label - 1]['name']

                    px = None
                    py = None
                    pxn = None
                    pyn = None
                    bw = None
                    bh = None
                    if output_polygons:
                        px = []
                        py = []
                        pxn = []
                        pyn = []
                        bw = ""
                        bh = ""
                        if 'detection_masks'in output_dict:
                            poly = mask_to_polygon(output_dict['detection_masks'][index], mask_threshold=mask_threshold,
                                                   mask_nth=mask_nth, view=(x0, y0, x1, y1), view_margin=view_margin,
                                                   fully_connected=fully_connected)
                            if len(poly) > 0:
                                px, py = polygon_to_lists(poly[0], swap_x_y=True, normalize=False)
                                pxn, pyn = polygon_to_lists(poly[0], swap_x_y=True, normalize=True, img_width=image.width, img_height=image.height)
                                if output_minrect:
                                    bw, bh = polygon_to_minrect(poly[0])
                                if bbox_as_fallback >= 0:
                                    if len(px) >= 3:
                                        p_x0n, p_y0n, p_x1n, p_y1n = polygon_to_bbox(lists_to_polygon(pxn, pyn))
                                        p_area = (p_x1n - p_x0n) * (p_y1n - p_y0n)
                                        b_area = (x1n - x0n) * (y1n - y0n)
                                        if (b_area > 0) and (p_area / b_area < bbox_as_fallback):
                                            px = [float(i) for i in [x0, x1, x1, x0]]
                                            py = [float(i) for i in [y0, y0, y1, y1]]
                                            pxn = [float(i) for i in [x0n, x1n, x1n, x0n]]
                                            pyn = [float(i) for i in [y0n, y0n, y1n, y1n]]
                                    else:
                                        px = [float(i) for i in [x0, x1, x1, x0]]
                                        py = [float(i) for i in [y0, y0, y1, y1]]
                                        pxn = [float(i) for i in [x0n, x1n, x1n, x0n]]
                                        pyn = [float(i) for i in [y0n, y0n, y1n, y1n]]
                                    if output_minrect:
                                        bw = x1 - x0 + 1
                                        bh = y1 - y0 + 1
                                if fit_bbox_to_polygon:
                                    if len(px) >= 3:
                                        x0, y0, x1, y1 = polygon_to_bbox(lists_to_polygon(px, py))
                                        x0n, y0n, x1n, y1n = polygon_to_bbox(lists_to_polygon(pxn, pyn))

                    roiobj = ROIObject(x0, y0, x1, y1, x0n, y0n, x1n, y1n, label, label_str, score=score,
                                       poly_x=px, poly_y=py, poly_xn=pxn, poly_yn=pyn,
                                       minrect_w=bw, minrect_h=bh)
                    roiobjs.append(roiobj)

                info = ImageInfo(os.path.basename(im_list[i]))
                roiext = (info, roiobjs)
                options = ["--output", str(tmp_dir if tmp_dir is not None else output_dir), "--no-images"]
                if output_width_height:
                    options.append("--size-mode")
                roiwriter = ROIWriter(options)
                roiwriter.save([roiext])
                if tmp_dir is not None:
                    os.rename(roi_path_tmp, roi_path)
        except:
            print("Failed processing images: {}".format(",".join(im_list)))
            print(traceback.format_exc())

        # Move finished images to output_path or delete it
        for i in range(len(im_list)):
            if delete_input:
                os.remove(im_list[i])
            else:
                os.rename(im_list[i], os.path.join(output_dir, os.path.basename(im_list[i])))

        end_time = datetime.now()
        inference_time = end_time - start_time
        inference_time = int(inference_time.total_seconds() * 1000)
        time_per_image = int(inference_time / len(im_list))
        if inference_times:
            l = ""
            for i in range(len(im_list)):
                l += ("{}|".format(os.path.basename(im_list[i])))
            l += ",{},{},{}\n".format(inference_time, len(im_list), time_per_image)
            times.append(l)
        print("  Inference + I/O time: {} ms\n".format(inference_time))
        total_time += inference_time

        if inference_times:
            with open(os.path.join(output_dir, "inference_time.csv"), "w") as time_file:
                for l in times:
                    time_file.write(l)
            with open(os.path.join(output_dir, "total_time.txt"), "w") as total_time_file:
                total_time_file.write("Total inference and I/O time: {} ms\n".format(total_time))
Exemple #3
0
 def test_complete_gif(self):
     self.assertTrue(is_image_complete(self.data_file("complete.gif")))
Exemple #4
0
 def test_complete_jpg(self):
     self.assertTrue(is_image_complete(self.data_file("complete.jpg")))
Exemple #5
0
 def test_empty_png(self):
     self.assertFalse(is_image_complete(self.data_file("empty.png")))
Exemple #6
0
 def test_unknown_type(self):
     try:
         is_image_complete(self.data_file("file.blah"))
         self.fail("should have failed with exception")
     except:
         pass
Exemple #7
0
 def test_empty_gif(self):
     self.assertFalse(is_image_complete(self.data_file("empty.gif")))
Exemple #8
0
 def test_incomplete_png(self):
     self.assertFalse(is_image_complete(self.data_file("incomplete.png")))
Exemple #9
0
 def test_incomplete_gif(self):
     self.assertFalse(is_image_complete(self.data_file("incomplete.gif")))
Exemple #10
0
def predict_on_images(model, input_dir, output_dir, tmp_dir, delete_input, clash_suffix="-in"):
    """
    Performs predictions on images found in input_dir and outputs the prediction PNG files in output_dir.

    :param model: the model to use
    :param input_dir: the directory with the images
    :type input_dir: str
    :param output_dir: the output directory to move the images to and store the predictions
    :type output_dir: str
    :param tmp_dir: the temporary directory to store the predictions until finished
    :type tmp_dir: str
    :param delete_input: whether to delete the input images rather than moving them to the output directory
    :type delete_input: bool
    :param clash_suffix: the suffix to use for clashes, ie when the input is already a PNG image
    :type clash_suffix: str
    """

    # counter for keeping track of images that cannot be processed
    incomplete_counter = dict()
    num_imgs = 1

    while True:
        start_time = datetime.now()
        im_list = []
        # Loop to pick up images equal to num_imgs or the remaining images if less
        for image_path in os.listdir(input_dir):
            # Load images only
            ext_lower = os.path.splitext(image_path)[1]
            if ext_lower in SUPPORTED_EXTS:
                full_path = os.path.join(input_dir, image_path)
                if auto.is_image_complete(full_path):
                    im_list.append(full_path)
                else:
                    if not full_path in incomplete_counter:
                        incomplete_counter[full_path] = 1
                    else:
                        incomplete_counter[full_path] = incomplete_counter[full_path] + 1

            # remove images that cannot be processed
            remove_from_blacklist = []
            for k in incomplete_counter:
                if incomplete_counter[k] == MAX_INCOMPLETE:
                    print("%s - %s" % (str(datetime.now()), os.path.basename(k)))
                    remove_from_blacklist.append(k)
                    try:
                        if delete_input:
                            print("  flagged as incomplete {} times, deleting\n".format(MAX_INCOMPLETE))
                            os.remove(k)
                        else:
                            print("  flagged as incomplete {} times, skipping\n".format(MAX_INCOMPLETE))
                            os.rename(k, os.path.join(output_dir, os.path.basename(k)))
                    except:
                        print(traceback.format_exc())

            for k in remove_from_blacklist:
                del incomplete_counter[k]

            if len(im_list) == num_imgs:
                break

        if len(im_list) == 0:
            time.sleep(1)
            break
        else:
            print("%s - %s" % (str(datetime.now()), ", ".join(os.path.basename(x) for x in im_list)))

        try:
            for i in range(len(im_list)):
                parts = os.path.splitext(os.path.basename(im_list[i]))
                if tmp_dir is not None:
                    out_file = os.path.join(tmp_dir, parts[0] + ".png")
                else:
                    out_file = os.path.join(output_dir, parts[0] + ".png")
                model.predict_segmentation(inp=im_list[i], out_fname=out_file)
        except:
            print("Failed processing images: {}".format(",".join(im_list)))
            print(traceback.format_exc())

        # Move finished images to output_path or delete it
        for i in range(len(im_list)):
            if delete_input:
                os.remove(im_list[i])
            else:
                # PNG input clashes with output, append suffix
                if im_list[i].lower().endswith(".png"):
                    parts = os.path.splitext(os.path.basename(im_list[i]))
                    os.rename(im_list[i], os.path.join(output_dir, parts[0] + clash_suffix + parts[1]))
                else:
                    os.rename(im_list[i], os.path.join(output_dir, os.path.basename(im_list[i])))

        end_time = datetime.now()
        inference_time = end_time - start_time
        inference_time = int(inference_time.total_seconds() * 1000)
        print("  Inference + I/O time: {} ms\n".format(inference_time))
Exemple #11
0
def predict(model,
            input_dir,
            output_dir,
            tmp_dir=None,
            top_k=5,
            score_threshold=0.0,
            delete_input=False,
            output_polygons=False,
            mask_threshold=0.1,
            mask_nth=1,
            output_minrect=False,
            view_margin=2,
            fully_connected='high',
            fit_bbox_to_polygon=False,
            output_width_height=False,
            bbox_as_fallback=False,
            scale=1.0,
            debayer="",
            continuous=False,
            output_mask_image=False):
    """
    Loads the model/config and performs predictions.

    :param model: the model to use
    :type model: Yolact
    :param input_dir: the directory to check for images to use for prediction
    :type input_dir: str
    :param output_dir: the directory to store the results in (predictions and/or images)
    :type output_dir: str
    :param tmp_dir: the directory to store the results initially, before moving them into the actual output directory
    :type tmp_dir: str
    :param top_k: the top X predictions (= objects) to parse
    :type top_k: int
    :param score_threshold: the score threshold to use
    :type score_threshold: float
    :param delete_input: whether to delete the images from the input directory rather than moving them to the output directory
    :type delete_input: bool
    :param output_polygons: whether the model predicts masks and polygons should be stored in the CSV files
    :type output_polygons: bool
    :param mask_threshold: the threshold to use for determining the contour of a mask
    :type mask_threshold: float
    :param mask_nth: to speed up polygon computation, use only every nth row and column from mask
    :type mask_nth: int
    :param output_minrect: when predicting polygons, whether to output the minimal rectangles around the objects as well
    :type output_minrect: bool
    :param view_margin: the margin in pixels to use around the masks
    :type view_margin: int
    :param fully_connected: whether regions of 'high' or 'low' values should be fully-connected at isthmuses
    :type fully_connected: str
    :param fit_bbox_to_polygon: whether to fit the bounding box to the polygon
    :type fit_bbox_to_polygon: bool
    :param output_width_height: whether to output x/y/w/h instead of x0/y0/x1/y1
    :type output_width_height: bool
    :param bbox_as_fallback: if ratio between polygon-bbox and bbox is smaller than this value, use bbox as fallback polygon, ignored if < 0
    :type bbox_as_fallback: float
    :param scale: the scale to use for the image (0-1)
    :type scale: float
    :param debayer: the OpenCV2 debayering type to use, eg COLOR_BAYER_BG2BGR; ignored if empty string or None
    :type debayer: str
    :param continuous: whether to delete the images from the input directory rather than moving them to the output directory
    :type continuous: bool
    :param output_mask_image: when generating masks, whether to output a combined mask image as well
    :type output_mask_image: bool
    """

    # counter for keeping track of images that cannot be processed
    incomplete_counter = dict()
    num_imgs = 1

    # evaluate debayering constant
    debayer_int = None
    if (debayer is not None) and debayer.startswith("COLOR_BAYER_"):
        debayer_int = int(eval("cv2." + debayer))

    while True:
        start_time = datetime.now()
        im_list = []
        # Loop to pick up images equal to num_imgs or the remaining images if less
        for image_path in os.listdir(input_dir):
            # Load images only
            ext_lower = os.path.splitext(image_path)[1]
            if ext_lower in SUPPORTED_EXTS:
                full_path = os.path.join(input_dir, image_path)
                if auto.is_image_complete(full_path):
                    im_list.append(full_path)
                else:
                    if not full_path in incomplete_counter:
                        incomplete_counter[full_path] = 1
                    else:
                        incomplete_counter[
                            full_path] = incomplete_counter[full_path] + 1

            # remove images that cannot be processed
            remove_from_blacklist = []
            for k in incomplete_counter:
                if incomplete_counter[k] == MAX_INCOMPLETE:
                    print("%s - %s" %
                          (str(datetime.now()), os.path.basename(k)))
                    remove_from_blacklist.append(k)
                    try:
                        if delete_input:
                            print(
                                "  flagged as incomplete {} times, deleting\n".
                                format(MAX_INCOMPLETE))
                            os.remove(k)
                        else:
                            print(
                                "  flagged as incomplete {} times, skipping\n".
                                format(MAX_INCOMPLETE))
                            os.rename(
                                k, os.path.join(output_dir,
                                                os.path.basename(k)))
                    except:
                        print(traceback.format_exc())

            for k in remove_from_blacklist:
                del incomplete_counter[k]

            if len(im_list) == num_imgs:
                break

        if len(im_list) == 0:
            if continuous:
                time.sleep(1)
                continue
            else:
                break
        else:
            print("%s - %s" % (str(datetime.now()), ", ".join(
                os.path.basename(x) for x in im_list)))

        try:
            for i in range(len(im_list)):
                roi_path = "{}/{}-rois.csv".format(
                    output_dir,
                    os.path.splitext(os.path.basename(im_list[i]))[0])
                img_path = "{}/{}-mask.png".format(
                    output_dir,
                    os.path.splitext(os.path.basename(im_list[i]))[0])
                if tmp_dir is not None:
                    roi_path_tmp = "{}/{}-rois.tmp".format(
                        tmp_dir,
                        os.path.splitext(os.path.basename(im_list[i]))[0])
                    img_path_tmp = "{}/{}-mask.tmp".format(
                        tmp_dir,
                        os.path.splitext(os.path.basename(im_list[i]))[0])
                else:
                    roi_path_tmp = "{}/{}-rois.tmp".format(
                        output_dir,
                        os.path.splitext(os.path.basename(im_list[i]))[0])
                    img_path_tmp = "{}/{}-mask.tmp".format(
                        output_dir,
                        os.path.splitext(os.path.basename(im_list[i]))[0])

                info, roiobjs, mask_comb = predict_image(
                    model,
                    im_list[i],
                    top_k=top_k,
                    score_threshold=score_threshold,
                    output_polygons=output_polygons,
                    mask_threshold=mask_threshold,
                    mask_nth=mask_nth,
                    output_minrect=output_minrect,
                    view_margin=view_margin,
                    fully_connected=fully_connected,
                    fit_bbox_to_polygon=fit_bbox_to_polygon,
                    bbox_as_fallback=bbox_as_fallback,
                    scale=scale,
                    debayer_int=debayer_int,
                    output_mask_image=output_mask_image)
                roiext = (info, roiobjs)
                options = [
                    "--output",
                    str(tmp_dir if tmp_dir is not None else output_dir),
                    "--no-images"
                ]
                if output_width_height:
                    options.append("--size-mode")
                roiwriter = ROIWriter(options)
                roiwriter.save([roiext])
                if tmp_dir is not None:
                    os.rename(roi_path_tmp, roi_path)

                if mask_comb is not None:
                    im = Image.fromarray(np.uint8(mask_comb), 'P')
                    im.save(img_path_tmp, "PNG")
                    os.rename(img_path_tmp, img_path)
        except:
            print("Failed processing images: {}".format(",".join(im_list)))
            print(traceback.format_exc())

        # Move finished images to output_path or delete it
        for i in range(len(im_list)):
            if delete_input:
                os.remove(im_list[i])
            else:
                os.rename(
                    im_list[i],
                    os.path.join(output_dir, os.path.basename(im_list[i])))

        end_time = datetime.now()
        inference_time = end_time - start_time
        inference_time = int(inference_time.total_seconds() * 1000)
        print("  Inference + I/O time: {} ms\n".format(inference_time))