diff --git a/doc/make_html.sh b/doc/make_html.sh index 5e2c7721..852ebfb4 100755 --- a/doc/make_html.sh +++ b/doc/make_html.sh @@ -1,3 +1,3 @@ -LD_LIBRARY_PATH="/usr/local/lib:$(pwd)/../../IkomiaCore/Build/lib:$(pwd)/../../gmic/build" +LD_LIBRARY_PATH="/usr/local/lib:$(pwd)/../../IkomiaCore/Build/lib:$(pwd)/../../gmic/build:$(pwd)/../../qwt/build/lib" export LD_LIBRARY_PATH -make html +sphinx-autobuild source build/html diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 00000000..8ff7c40e --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,6 @@ +furo +myst-parser +sphinx-inline-tabs +sphinx-autobuild +sphinx-copybutton +sphinxcontrib-mermaid diff --git a/doc/source/_autosummary/_autosummaryv/ikomia.dataprocess.pydataprocess.CPluginProcessInterface.rst b/doc/source/_autosummary/_autosummaryv/ikomia.dataprocess.pydataprocess.CPluginProcessInterface.rst index fb0138c1..a983fe39 100644 --- a/doc/source/_autosummary/_autosummaryv/ikomia.dataprocess.pydataprocess.CPluginProcessInterface.rst +++ b/doc/source/_autosummary/_autosummaryv/ikomia.dataprocess.pydataprocess.CPluginProcessInterface.rst @@ -16,7 +16,7 @@ CPluginProcessInterface ~CPluginProcessInterface.get_process_factory ~CPluginProcessInterface.get_widget_factory - +.. See this :doc:`example<../../hello_world_plugin_interface>` for implementation details. diff --git a/doc/source/_static/aerial_airplanes.jpg b/doc/source/_static/aerial_airplanes.jpg new file mode 100644 index 00000000..ea32782b Binary files /dev/null and b/doc/source/_static/aerial_airplanes.jpg differ diff --git a/doc/source/_static/aerial_airplanes_box.png b/doc/source/_static/aerial_airplanes_box.png new file mode 100644 index 00000000..8b182da5 Binary files /dev/null and b/doc/source/_static/aerial_airplanes_box.png differ diff --git a/doc/source/_static/aerial_airplanes_trained.png b/doc/source/_static/aerial_airplanes_trained.png new file mode 100644 index 00000000..0b70ac97 Binary files /dev/null and b/doc/source/_static/aerial_airplanes_trained.png differ diff --git a/doc/source/_static/display_graphics.png b/doc/source/_static/display_graphics.png new file mode 100644 index 00000000..8af23a37 Binary files /dev/null and b/doc/source/_static/display_graphics.png differ diff --git a/doc/source/_static/display_inst_seg.png b/doc/source/_static/display_inst_seg.png new file mode 100644 index 00000000..df9b82de Binary files /dev/null and b/doc/source/_static/display_inst_seg.png differ diff --git a/doc/source/_static/display_pose.png b/doc/source/_static/display_pose.png new file mode 100644 index 00000000..5c9a0137 Binary files /dev/null and b/doc/source/_static/display_pose.png differ diff --git a/doc/source/_static/display_semantic.png b/doc/source/_static/display_semantic.png new file mode 100644 index 00000000..5dfdcace Binary files /dev/null and b/doc/source/_static/display_semantic.png differ diff --git a/doc/source/_static/ik_algo_by_name.png b/doc/source/_static/ik_algo_by_name.png new file mode 100644 index 00000000..3017bca8 Binary files /dev/null and b/doc/source/_static/ik_algo_by_name.png differ diff --git a/doc/source/_static/ik_algo_parameters.png b/doc/source/_static/ik_algo_parameters.png new file mode 100644 index 00000000..23f32746 Binary files /dev/null and b/doc/source/_static/ik_algo_parameters.png differ diff --git a/doc/source/_static/img_blur.jpg b/doc/source/_static/img_blur.jpg new file mode 100644 index 00000000..b576fcf9 Binary files /dev/null and b/doc/source/_static/img_blur.jpg differ diff --git a/doc/source/_static/img_canny.jpg b/doc/source/_static/img_canny.jpg new file mode 100644 index 00000000..9a6cc6c3 Binary files /dev/null and b/doc/source/_static/img_canny.jpg differ diff --git a/doc/source/_static/img_canny_thres.jpg b/doc/source/_static/img_canny_thres.jpg new file mode 100644 index 00000000..232b1515 Binary files /dev/null and b/doc/source/_static/img_canny_thres.jpg differ diff --git a/doc/source/_static/img_face.jpg b/doc/source/_static/img_face.jpg new file mode 100644 index 00000000..6bcffcc0 Binary files /dev/null and b/doc/source/_static/img_face.jpg differ diff --git a/doc/source/_static/img_people.jpg b/doc/source/_static/img_people.jpg new file mode 100644 index 00000000..cde18fb3 Binary files /dev/null and b/doc/source/_static/img_people.jpg differ diff --git a/doc/source/_static/img_work.jpg b/doc/source/_static/img_work.jpg new file mode 100644 index 00000000..65479495 Binary files /dev/null and b/doc/source/_static/img_work.jpg differ diff --git a/doc/source/_static/img_yolo.jpg b/doc/source/_static/img_yolo.jpg new file mode 100644 index 00000000..7c59d61a Binary files /dev/null and b/doc/source/_static/img_yolo.jpg differ diff --git a/doc/source/advanced_guide/IO_management.md b/doc/source/advanced_guide/IO_management.md new file mode 100644 index 00000000..84999a06 --- /dev/null +++ b/doc/source/advanced_guide/IO_management.md @@ -0,0 +1,281 @@ +# Input/Output management + +Each algorithm in Ikomia specifies a set of inputs and outputs. The type of inputs and outputs may vary depending on the selected algorithm. + +This documentation provides a comprehensive list of I/O types to address common needs in Computer Vision. + +Let's take the example of YOLO v7 algorithm : +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik + +wf = Workflow() + +yolov7 = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) +``` +## `Print()` is your best friend + +### Inputs + +```python +print(yolov7.get_inputs()) +``` +This produces the following output : +```shell +[CImageIO(IODataType.IMAGE, CImageIO, /home/yom/Images/dog.jpg), CGraphicsInput(CGraphicsInput)] +``` +To access inputs, you just have to do the following: +```python +input_obj = yolov7.get_input(input_index) +``` +If input_index = 0, `input_obj` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO`. + +If input_index = 1, `input_obj` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CGraphicsInput`. + +### Outputs + +```python +print(yolov7.get_outputs()) +``` +This produces the following output : +```shell +[CImageIO(IODataType.IMAGE, CImageIO, /home/yom/Images/dog.jpg), CObjectDetectionIO()] +``` +To access outputs, you just have to do the following: +```python +output_obj = yolov7.get_output(output_index) +``` +If output_index = 0, `input_obj` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO`. + +If output_index = 1, `input_obj` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO`. + +You can now handle each input/output according to its type. + +## Common I/O + +### Image + +In Ikomia, an image is an object of type {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and the most common function is {py:func}`~ikomia.dataprocess.pydataprocess.CImageIO.get_image` +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik + +wf = Workflow() + +yolov7 = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) + +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_dog.png") + +input_obj = yolov7.get_input(0) # first input +output_obj = yolov7.get_output(0) # first output + +img_in = input_obj.get_image() +img_out = output_obj.get_image() +``` +The {py:meth}`~ikomia.dataprocess.pydataprocess.CImageIO.get_image` function returns an image as a numpy array with dimensions [HWC]. When the number of channels is 3, the color format should be RGB. + +## Object Detection I/O + +To better deal with Object Detection algorithms such as YOLO or EfficientDet, we provide a convenient I/O ({py:mod}`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO`) which stores all objects ({py:mod}`~ikomia.dataprocess.pydataprocess.CObjectDetection`) with the following information: + +* Class label +* Confidence +* Bounding box + +When you have a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and a {py:mod}`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO` as outputs, you can easily burn bounding boxes on your image with {py:func}`~ikomia.dataprocess.pydataprocess.CImageIO.get_image_with_graphics` + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +wf = Workflow() + +yolov7 = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) + +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_dog.png") + +img = yolov7.get_image_with_graphics() + +display(img) +``` +![](../_static/display_graphics.png) + +If you just want the results, use : + +```python +# Get results as object +results = yolov7.get_results() + +# Get results as JSON +results_json = results.to_json() +``` +`results` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO`. + +If you want to iterate over the results : +```python +# Get all detected objects +objects = results.get_objects() +# Iterate over all objects +for obj in objects: + # Do stuff here on your objects + print("==================================") + print(f"id: {obj.id}") + print(f"label: {obj.label}") + print(f"confidence: {obj.confidence}") + print(f"box: {obj.box}") + print(f"color: {obj.color}") +``` +It will output: +```shell +================================== +id: 0 +label: bench +confidence: 0.93017578125 +box: [34.0, 224.0, 433.0, 270.0] +color: [12, 230, 160] +================================== +id: 1 +label: dog +confidence: 0.65234375 +box: [175.0, 117.0, 136.0, 250.0] +color: [2, 139, 119] +``` +## Object Segmentation I/O + +### Instance Segmentation I/O + +To better deal with Instance Segmentation algorithms such as MaskRCNN or SparseInst, we provide a convenient I/O ({py:mod}`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO`) which stores all objects ({py:mod}`~ikomia.dataprocess.pydataprocess.CInstanceSegmentation`) with the following information: + +* Class label +* Confidence +* Bounding box = [x, y, width, height] +* Binary mask = numpy array + +When you have a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and a {py:mod}`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO` as outputs, you can display different results : + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +wf = Workflow() + +yolov7 = wf.add_task(ik.infer_yolo_v7_instance_segmentation(), auto_connect=True) + +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_dog.png") + +display(yolov7.get_image_with_graphics()) +display(yolov7.get_image_with_mask()) +display(yolov7.get_image_with_mask_and_graphics()) +``` +![](../_static/display_inst_seg.png) + +If you just want the results, use : + +```python +# Get results as object +results = yolov7.get_results() + +# Get results as JSON +results_json = results.to_json() +``` +`results` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO`. + +If you want to iterate over the results : +```python +# Get all detected objects +objects = results.get_instances() +# Iterate over all objects +for obj in objects: + # Do stuff here on your objects + print("==================================") + print(f"id: {obj.id}") + print(f"type: {obj.type}") + print(f"class_index: {obj.class_index}") + print(f"confidence: {obj.confidence}") + print(f"box: {obj.box}") + print(f"color: {obj.color}") + display(obj.mask*255) +``` + +### Semantic Segmentation I/O + +To better deal with Semantic Segmentation algorithms such as DeepLabV3+ or UNet, we provide a convenient I/O ({py:mod}`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO`) which stores the following information: + +* Grayscale mask = labelled image where each pixel has a specific value corresponding to its class +* Class names = list associated with the semantic mask + +When you have a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and a {py:mod}`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO` as outputs, you can overlay the mask on the image : + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +wf = Workflow() + +yolov7 = wf.add_task(ik.infer_hf_semantic_segmentation(), auto_connect=True) + +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_dog.png") + +display(yolov7.get_image_with_mask()) +``` +![](../_static/display_semantic.png) + +```python +# Get results as object +results = yolov7.get_results() + +# Get results as JSON +results_json = results.to_json() +``` +`results` is a {py:mod}`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO`. + +If you want to exploit the results : +```python +# Get the mask and associated class names +mask = results.get_mask() +classes = results.get_class_names() +print(classes) + +# Display class number 2 = sky +mask_from_class = (mask == 2) +display(mask_from_class) +``` +## Pose Estimation I/O + +To better deal with pose estimation algorithms, we provide a convenient I/O ({py:mod}`~ikomia.dataprocess.pydataprocess.CKeypointsIO`) which stores all objects ({py:mod}`~ikomia.dataprocess.pydataprocess.CObjectKeypoints` and {py:mod}`~ikomia.dataprocess.pydataprocess.CKeypointLink`) with the following information: + +Keypoints: +* Label +* Confidence +* Bounding box = [x, y, width, height] +* Points = list of points (x,y) + +Link: +* Starting point index +* Ending point index +* Label + +When you have a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and a {py:mod}`~ikomia.dataprocess.pydataprocess.CKeypointsIO` as outputs, you can burn graphics on your image : + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +wf = Workflow() + +pose = wf.add_task(ik.infer_detectron2_keypoints(), auto_connect=True) + +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_fireman.jpg") + +display(pose.get_image_with_graphics()) +``` +![](../_static/display_pose.png) \ No newline at end of file diff --git a/doc/source/advanced_guide/advanced_guide.md b/doc/source/advanced_guide/advanced_guide.md new file mode 100644 index 00000000..cdd84135 --- /dev/null +++ b/doc/source/advanced_guide/advanced_guide.md @@ -0,0 +1,54 @@ +# Advanced Ikomia Guide + +## Table of Contents +1. [Custom Algorithms](#custom-algorithms) +2. [Advanced Workflow Management](#advanced-workflow-management) +3. [Performance Optimization](#performance-optimization) +4. [Integration with External Tools](#integration-with-external-tools) +5. [Advanced Visualization](#advanced-visualization) +6. [Model Training and Evaluation](#model-training-and-evaluation) +7. [Deployment](#deployment) + +## Custom Algorithms + +- Creating custom algorithms +- Integrating custom algorithms into Ikomia workflows +- Best practices for writing efficient and reusable code + +## Advanced Workflow Management + +- Managing complex workflows with multiple algorithms +- Branching and parallel processing in workflows + +## Performance Optimization + +- GPU acceleration +- Batch processing +- Memory management + +## Integration with External Tools + +- Integrating Ikomia with Jupyter notebooks +- Integrating Ikomia with cloud services +- Integrating Ikomia with custom web applications + +## Advanced Visualization + +- Creating interactive plots +- 3D renderings +- Animations + +## Model Training and Evaluation + +- Training machine learning models with Ikomia +- Hyperparameter tuning +- Cross-validation +- Performance metrics + +## Deployment + +- Deploying Ikomia workflows in production environments +- Containerization +- API development +- Monitoring + diff --git a/doc/source/advanced_guide/ik_namespace.md b/doc/source/advanced_guide/ik_namespace.md new file mode 100644 index 00000000..d2af8d16 --- /dev/null +++ b/doc/source/advanced_guide/ik_namespace.md @@ -0,0 +1,84 @@ +# The `ik` auto-completion system + +The`ik` namespace is an auto-completion system designed to facilitate algorithm search and settings. + +An algorithm is a set of instructions that a computer program follows to perform a specific task or solve a particular problem. +For example, an algorithm can be used to sort a list of numbers or detect faces in an image. When you're developing a program, you may want to use an algorithm that someone else has already created to save time and effort. + +**Algorithm search** is the process of finding and selecting an algorithm that meets your needs. +In the context of the `ik` namespace described in the documentation you provided, algorithm search refers to the process of finding and selecting algorithms that are available through the Ikomia system, either locally on your machine or through the Ikomia HUB. + +**Algorithm settings** refer to the parameters or options that can be adjusted to customize the behavior of an algorithm. +For example, if you're using an algorithm to detect faces in an image, you may be able to adjust settings such as the minimum size of a detected face or the level of confidence required for a detection. +Adjusting these settings can help you achieve better results depending on your specific needs. +In the context of the `ik` namespace, algorithm settings can be adjusted using a function-like syntax that allows you to set the parameters of an algorithm in your code. + +## The `ik` structure + +When you use Ikomia API for the first time, it creates 3 files listing all available algorithms in the Ikomia environment. + +* `auto_complete.local` : this file contains all algorithms already installed on your machine +* `auto_complete.online` : this file contains all algorithms from Ikomia HUB +* `ik.py` : this file contains all algorithms (local and online) + +In `ik.py`, each algorithm is described with the same pattern : +* Parameters as class attribute +* `__new__` overload for function-like settings +* a static method to retrieve the name of the algorithm + +```python +class ocv_stack_blur: + kSizeHeight = "kSizeHeight" + kSizeWidth = "kSizeWidth" + + def __new__(cls, kSizeHeight: str="5", kSizeWidth: str="5"): + algo = ikomia.ik_registry.create_algorithm("ocv_stack_blur", None) + algo.set_parameters({ + "kSizeHeight": kSizeHeight, + "kSizeWidth": kSizeWidth, + }) + return algo + + @staticmethod + def name(): + return "ocv_stack_blur" +``` + +## Algorithm search + +You can find all the algorithms offered by Ikomia by visiting the [Ikomia HUB](https://github.com/Ikomia-hub) repository on GitHub. + +However, as a developer, you need to easily access all algorithms in an intuitive and ergonomic manner as you are coding. That's why we created the ik namespace, which is a suitable tool for IDEs (such as PyCharm, VSCode) or notebooks. + +![](../_static/ik_algo_by_name.png) + +```{warning} +If you're scripting in a text editor or by command line, the `ik` auto-completion won't work. +``` + +## Algorithm settings + +As with algorithm search, every coder may want to easily set parameters to test functions. That's why we adopted a function-like method to set algorithm parameters. + +![](../_static/ik_algo_parameters.png) + +Here is a code example of algorithm settings : +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +wf = Workflow() + +face_detector = wf.add_task(ik.infer_face_detection_kornia(), auto_connect=True) +# face_detector = wf.add_task(ik.infer_face_detection_kornia(conf_thres="0.2"), auto_connect=True) +# face_detector = wf.add_task(ik.infer_face_detection_kornia(conf_thres="0.9"), auto_connect=True) + +blur = wf.add_task(ik.ocv_stack_blur(), auto_connect=True) +# blur = wf.add_task(ik.ocv_stack_blur(kSizeHeight="15", kSizeWidth="15"), auto_connect=True) +# blur = wf.add_task(ik.ocv_stack_blur(kSizeHeight="61", kSizeWidth="61"), auto_connect=True) + +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_people.jpg") + +display(blur.get_output(0).get_image()) +``` \ No newline at end of file diff --git a/doc/source/advanced_guide/index.md b/doc/source/advanced_guide/index.md new file mode 100644 index 00000000..0b8ffbf3 --- /dev/null +++ b/doc/source/advanced_guide/index.md @@ -0,0 +1,208 @@ +# Going deeper with workflows + +```{toctree} +:hidden: + +ik_namespace +IO_management +save_and_load_workflow +``` + +By the end of this guide, you will have a deeper understanding of how to use the Ikomia API to create complex image processing workflows. + +## Step-by-step explanations + +Code example : +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Init the workflow +wf = Workflow() + +# Add and connect algorithms +face = wf.add_task(ik.infer_face_detection_kornia(), auto_connect=True) +blur = wf.add_task(ik.ocv_blur(kSizeWidth="61", kSizeHeight="61"), auto_connect=True) + +# Run on your image +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_people.jpg") + +# Inspect results +display(face.get_image_with_graphics()) +display(blur.get_output(0).get_image()) +``` +Kornia Face Detector | Blurred faces +:-------------------------:|:-------------------------: +![](../_static/img_face.jpg) | ![](../_static/img_blur.jpg) + +This code showcases how to use the Ikomia API to create a simple image processing workflow : blurring face in images. + +Let's use this example as a starting point. + +### 1. Import +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik +``` +These lines import the required classes and functions from the Ikomia API. + +{py:class}`~ikomia.dataprocess.workflow.Workflow` is the base class to create a workflow object. + +{py:meth}`~ikomia.utils.displayIO.display` is a useful tool to display images based on the PIL library. + +`ik` is an auto-completion system designed to facilitate algorithm search and settings (see [here](ik_namespace) for more information) + +### 2. Create Workflow +```python +wf = Workflow() +``` +This line creates a new {py:class}`~ikomia.dataprocess.workflow.Workflow` object, which will be used to manage the tasks in the workflow. + +### 3. Add and connect algorithm + +There are 2 ways to add algorithms to your workflow thanks to the {py:meth}`~ikomia.dataprocess.workflow.Workflow.add_task` function. + +#### Add by name + +The first one is to simply use the name of the algorithm you want to test: + +```python +face = wf.add_task(name="infer_face_detection_kornia", auto_connect=True) +``` + +#### Add by auto-completion + +When you don't know exactly the name, you can use the `ik` namespace to search algorithms: + +```python +face = wf.add_task(ik.infer_face_detection_kornia(), auto_connect=True) +``` + +The `auto_connect=True` parameter means that the output of the previous task (if any) will be automatically connected to the input of this task. + +#### Connect manually + +In some cases, you might want to connect manually your algorithms. In that case, you can do the following: +```python +face = wf.add_task(ik.infer_face_detection_kornia()) +wf.connect_tasks(wf.root(), face) + +blur = wf.add_task(ik.ocv_blur(kSizeWidth="61", kSizeHeight="61")) +wf.connect_tasks(face, blur, [(0,0), (1,1)]) +``` +The {py:meth}`~ikomia.dataprocess.workflow.Workflow.root` function is the root node of any workflow and contains input data (images, videos etc...). +The {py:meth}`~ikomia.dataprocess.workflow.Workflow.connect_tasks` function automatically establishes a connection between two tasks, if the indexes are not specified. +If the indices are provided, the function connects the output index of the source task with the input index of the target task + +### 4. Algorithm parameters tuning + +#### By auto-completion + +```python +blur = wf.add_task(ik.ocv_blur(kSizeWidth="61", kSizeHeight="61"), auto_connect=True) +``` +This line adds a blur effect task to the workflow using OpenCV's blur function. +The `kSizeWidth` and `kSizeHeight` parameters define the size of the kernel used for blurring. + +#### By a Dict approach + +Another way to set parameters is to use the **task object** directly and the `ik` auto-completion system for parameters name retrieval: +```python +blur.set_parameters({ + ik.ocv_blur.kSizeWidth: "61", + ik.ocv_blur.kSizeHeight: "61" +}) +``` + +### 5. Apply your workflow on your image + +There are 3 ways to apply workflows on images with the {py:meth}`~ikomia.dataprocess.workflow.Workflow.run_on` function. + +#### From image path + +Use the path to your image, then Ikomia loads and runs the workflow on this image: +```python +wf.run_on(path="path/to/your/image.png") +``` + +#### From image buffer + +Most of the time, you work with image objects (numpy or OpenCV), in this case you can do the following: +```python +import cv2 +img = cv2.imread("/path/to/your/image.png") + +wf.run_on(img) +``` + +#### From image URL + +When using images from the web, you can directly use their URLs: +```python + wf.run_on(url="https://www.url-image.com") +``` + +#### From folder (batch processing) + +In some cases, you may want to apply the same workflow on multiple images (batch processing). + +To do so with Ikomia, just place your images in a folder and run on that folder : +```python +wf.run_on(folder="/path/to/your/folder") +``` + +### 5. Managing outputs + +Ikomia provides a lot of different outputs depending on the algorithm category (object detection, object segmentation, pose estimation). + +To get a detailed overview, please read this [chapter](IO_management). + +When you want to visually inspect your results but you are not sure of the available outputs, just use a print on a task object: +```python +print(face.get_outputs()) +``` +It will show the task outputs information in your console: + +```shell +[CImageIO(IODataType.IMAGE, CImageIO), CObjectDetectionIO()] +``` + +Accessing the output results of a task always follows the same pattern: +1. `face.get_output(n)` where n is the nth output of the task (starting at 0) + +#### Single image + +If the output is of type CImageIO, you can get a numpy image with : + +* `face.get_output(n).get_image()` : get numpy array image + +#### Single image with graphics (bounding boxes) + +* `face.get_image_with_graphics()` : get numpy image with burned graphics such as bounding boxes, text, points or polygons on your input image. + +#### Results as objects + +* `face.get_results()` which returns an object containing all results +* `face.get_results().get_objects()` which returns a list of all objects + +#### Results as JSON + +* `face.get_results().to_json()` which returns your results in JSON format + + +### 6. Display your results + +Ikomia provides a useful tool to easily display your image results. + +Based on the PIL image library, you can now inspect your results in one line of code. +```python +display(face.get_image_with_graphics()) +``` +![](../_static/img_face.jpg) +```python +display(blur.get_output(0).get_image()) +``` +![](../_static/img_blur.jpg) + diff --git a/doc/source/advanced_guide/save_and_load_workflow.md b/doc/source/advanced_guide/save_and_load_workflow.md new file mode 100644 index 00000000..409f2329 --- /dev/null +++ b/doc/source/advanced_guide/save_and_load_workflow.md @@ -0,0 +1,57 @@ +# Save and load your workflow + +## Save your workflow + +```python +wf.save("path/to/my_workflow.json") +``` +If you want to save your workflow, you can export it in JSON format. This export will save all algorithms, parameters, model paths and connections in a descriptive file. + +This file enables you to share your work or easily reuse it on any computing device. + +## Load and run your workflow + +Basic script for loading workflows. + +```python +from ikomia.dataprocess.workflow import Workflow + +# Init the workflow +wf = Workflow() + +# Load the workflow +wf.load("path/to/my_workflow.json") + +# Run on your image +wf.run_on(path="path/to/your/image.png") +``` + +## Modify the workflow + +First you can get all tasks from the workflow with : +```python +print(wf.get_tasks()) +``` +For example, you can obtain this kind of output : +```shell +[CWorkflowTask(Root), CObjectDetectionTask(infer_yolo_v7), C2dImageTask(ocv_stack_blur, 1)] +``` +Then, you can easily access each task by searching by name: +```python +task = wf.find_task("task_name") +``` +Or +```python +task = wf.find_task(ik.task_name()) +``` +See [`ik` auto-completion](ik_namespace) for more information. + +Finally, adjust the parameters : + +```python +task.set_parameters({ + ik.task_name.param_1: "value", + ik.task_name.param_2: "value" +}) +``` +And you're done ! \ No newline at end of file diff --git a/doc/source/bonus/virtual_env.md b/doc/source/bonus/virtual_env.md new file mode 100644 index 00000000..ad150d6e --- /dev/null +++ b/doc/source/bonus/virtual_env.md @@ -0,0 +1,31 @@ +# How to create a virtual environment + +### Creating a Virtual Environment + +Before installing the Ikomia API, it's recommended to create a virtual environment. This helps to isolate your project's dependencies and avoid conflicts with other packages. + +To create a virtual environment, follow these steps: + +#### 1. Install the virtualenv package if you haven't already +```shell +pip install virtualenv +``` + +#### 2. Create a new virtual environment in your selected directory +```shell +virtualenv my_ikomia_env +```` +Replace my_ikomia_env with the name you'd like to give to your virtual environment. + +#### 3. Activate the virtual environment + +On Windows: +```shell +my_ikomia_env\Scripts\activate +```` + +On Linux or macOS: +```shell +source my_ikomia_env/bin/activate +```` +Now that your virtual environment is active, you can proceed with the installation of the Ikomia API. \ No newline at end of file diff --git a/doc/source/classification/index.md b/doc/source/classification/index.md new file mode 100644 index 00000000..956ecb44 --- /dev/null +++ b/doc/source/classification/index.md @@ -0,0 +1,25 @@ +# First steps in Image Classification with Ikomia API + +This guide will help you get started with classification tasks using the Ikomia API. We will cover both inference and training aspects. + +## Inference + +Inference is the process of using a pre-trained model to classify new, unseen data. To perform inference with the Ikomia API, follow these steps: + +1. **Load the pre-trained model**: Import the model you want to use for classification. +2. **Preprocess the input data**: Prepare the input data according to the model requirements (e.g., resizing, normalization). +3. **Perform the classification**: Use the pre-trained model to classify the input data. +4. **Post-process the results**: Analyze and visualize the classification results. + +## Training + +Training is the process of creating a classification model from a dataset. To train a model using the Ikomia API, follow these steps: + +1. **Prepare the dataset**: Organize and preprocess the dataset for training (e.g., data augmentation, splitting into training and validation sets). +2. **Define the model architecture**: Design the structure of the neural network or choose a pre-defined architecture. +3. **Configure the training parameters**: Set up the training parameters such as learning rate, batch size, and number of epochs. +4. **Train the model**: Start the training process and monitor the progress. +5. **Evaluate the model performance**: Assess the performance of the trained model using various metrics and visualization tools. + + +For more detailed information and examples, refer to the [Ikomia API documentation](https://ikomia.com/docs/api/). diff --git a/doc/source/conf.py b/doc/source/conf.py index 0578823a..abf7f354 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = 'Ikomia API' -copyright = '2020, Ikomia SAS' +copyright = '2023, Ikomia SAS' author = 'Ludovic Barusseau' # The full version, including alpha/beta/rc tags @@ -35,7 +35,10 @@ 'sphinx.ext.coverage', 'sphinx.ext.napoleon', 'sphinx.ext.autosectionlabel', - 'sphinx_rtd_theme', + 'sphinx_copybutton', + 'sphinx_inline_tabs', + 'myst_parser', + 'sphinxcontrib.mermaid' ] # Add any paths that contain templates here, relative to this directory. @@ -52,15 +55,14 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -#html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +html_theme = 'furo' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -html_css_files = ['ikomia.css', ] +# html_css_files = ['ikomia.css', ] html_logo = '_static/app.png' @@ -68,45 +70,13 @@ autosummary_generate = False # Style customization - Alabaster -#html_theme_options = { -# 'description': 'A shared vision of research', -# 'fixed_sidebar': 'true', -# 'logo': 'app.png', -# 'logo_name': 'true', -# 'logo_text_align': 'center', -# 'github_button': 'true', -# 'github_user': 'Ikomia-dev', -# 'github_repo': '/', -# 'extra_nav_links': { -# 'Website': 'https://ikomia.com', -# 'Blog': 'https://blog.ikomia.com'}, -# 'show_powered_by': 'false', -# 'show_relbars': 'true', - - #colors -# 'link': '#cc5a20', -# 'pre_bg': '#fcf0ea', -# 'link_hover': '#944117', -# 'sidebar_header': '#303030', -# 'sidebar_link': '#cc5a20', -# 'font_size': '15px', -# 'sidebar_width': '250px' -#} - -# Style customization - ReadTHeDocs html_theme_options = { - #'analytics_id': 'UA-XXXXXXX-1', # Provided by Google in your dashboard - #'analytics_anonymize_ip': False, - 'logo_only': False, - 'display_version': True, - 'prev_next_buttons_location': 'both', - 'style_external_links': False, - 'vcs_pageview_mode': 'blob', - 'style_nav_header_background': '#150E83', - # Toc options - 'collapse_navigation': True, - 'sticky_navigation': True, - 'navigation_depth': 3, - 'includehidden': True, - 'titles_only': False + "light_css_variables": { + # "color-sidebar-caption-text": "#CC5A20", + # "font-stack": "_static/Avenue Mono.woff2", # Regular text + # "font-stack--monospace": "_static/n27-regular-webfont.ttf", # Code blocks + inline code + }, } + +pygments_style = "friendly" +pygments_dark_style = "native" diff --git a/doc/source/dependencies.rst b/doc/source/dependencies.rst deleted file mode 100644 index ca1a5cfd..00000000 --- a/doc/source/dependencies.rst +++ /dev/null @@ -1,58 +0,0 @@ -Dependencies management -======================= - -As of any Python project, an Ikomia plugin may have some Python module dependencies. -The philosophy behind Ikomia is to offer ready to use algorithms to users. -From the plugin author perspective, it means that the plugin must include directives -to install these dependencies automatically. - -To achieve this goal, Ikomia software includes a system based on pip requirements files. -During the plugin installation, Ikomia software will parse the plugin directory to find requirements files -and install dependencies automatically. - -.. note:: Before publishing plugins, authors must include the necessary requirements files. - - -Requirements file structure ---------------------------- - -Ikomia dependency management is fully based on pip. Please consult the pip official documentation -to know about all features: - -- `pip user guide `_ -- `requirements file format `_ - - -Multi-steps installation ------------------------- - -In some cases, it could be necessary to split the installation process to force installation of dependencies -prior to others. As such, Ikomia dependency system handles multiple requirements files -and apply alphanumeric sort to define installation order. Authors can then insert several requirements file into the -plugin directory to solve dependencies issues. - -Example of plugin structure: - -- MyPlugin - - - __init__.py - - my_plugin.py - - my_plugin_process.py - - my_plugin_widget.py - - requirements1.txt - - requirements2.txt - -In this configuration, Ikomia software will first install Python packages listed in *requirements1.txt* and -then those listed in the file *requirements2.txt*. - - -Limitations ------------ - -The standard way to manage dependencies in Python and its pip package installer is to provide a valid *setup.py* script. -Then, Python package can either be distributed from Wheel or from source. For the moment, Ikomia software can only install -dependencies available in the official Python Package Index (PyPI) or via a git repository. Support for manual installation -through direct call to *setup.py* script (setuptools) inside the plugin is not yet available. - - -.. important:: While implementing your own algorithm, you may need to add dependencies with C extensions. So you should have installed on your own a valid C/C++ compiler for your system. \ No newline at end of file diff --git a/doc/source/display_tools.rst b/doc/source/display_tools.rst deleted file mode 100644 index 6d59d220..00000000 --- a/doc/source/display_tools.rst +++ /dev/null @@ -1,40 +0,0 @@ -Display tools for debugging -=========================== - -The :py:mod:`~ikomia.dataprocess.displayIO` module aims to give display output based on Matplolib for every Ikomia input/output types. -We provide these features for debugging purpose essentially. - -So it's very simple, you just have to call a single function: :py:meth:`~ikomia.dataprocess.displayIO.display`. - -.. code-block:: python - - from ikomia.dataprocess import workflow, displayIO - - wf = workflow.create("ObjectDetection") - yolov4_id, yolov4_obj = wf.add_task("infer_yolo_v4") - wf.connect_tasks(wf.getRootID(), yolov4_id) - - wf.run_on(path="path/to/image.png") - - # Display image output - img_output = wf.get_image_output(yolov4_id) - displayIO.display(img_output) - - # Display graphics output - graphics_output = wf.get_graphics_output(yolov4_id) - displayIO.display(graphics_output) - - # Display blob measures output - box_output = wf.get_blob_measure_output(yolov4_id) - displayIO.display(box_output) - - -You can also apply the :py:meth:`~ikomia.dataprocess.displayIO.display` on: - -- **task** object instance: this will show a figure with inputs and outputs of the given task. -- **workflow** object instance: this will show a GraphViz representation of the workflow. - -.. important:: - Matplotlib is used to generate almost all figures, so you have to make sure you have a valid GUI backend to display - the figures. This will, for example, not work on Linux machine or docker image where no X server is installed. - diff --git a/doc/source/examples.rst b/doc/source/examples.rst deleted file mode 100644 index 41eda91c..00000000 --- a/doc/source/examples.rst +++ /dev/null @@ -1,35 +0,0 @@ -Examples -======== - -Hello World plugin ------------------- - -.. toctree:: - :maxdepth: 2 - - hello_world_plugin_interface - hello_world_plugin_process - hello_world_plugin_widget - - -Simple OpenCV plugin --------------------- - -.. toctree:: - :maxdepth: 2 - - opencv_plugin_interface - opencv_plugin_process - opencv_plugin_widget - - -Interactive plugin ------------------- - -- `Plugin interface `_ - -- `Process `_ - -- `Widget `_ - -- `Requirements `_ diff --git a/doc/source/first_steps_workflow.rst b/doc/source/first_steps_workflow.rst deleted file mode 100644 index 86e3f322..00000000 --- a/doc/source/first_steps_workflow.rst +++ /dev/null @@ -1,189 +0,0 @@ -First steps with workflows -========================== - -Workflows are acyclic directed graph composed by nodes (algorithms) and connections from node outputs to adjacent node inputs. Output and inputs must have compatible data types to be connected, otherwise connection -will fail and raise exception. The API provides all features needed to handle such graph: - -- create nodes (algorithms) identified by their unique name -- connect them through their I/O -- set the workflow global inputs -- set algorithm parameters -- run workflows -- save workflows to file -- load workflows from file - - -Get the list of available algorithms ------------------------------------- - -In Ikomia, algorithms are identified by their names. So one of the most important thing when using this API is to know the list of possible algorithms. -We can differentiate 2 kinds of algorithms: those available on the host system (built-in + installed plugins) and those available on Ikomia HUB. -As introduced in the previous section, algorithms management is done by the global Ikomia registry. - -Get names of built-in and installed algorithms: - -.. code-block:: python - - import ikomia - - names = ikomia.ik_registry.getAlgorithms() - -Get information (name, authors, description...) of Ikomia HUB algorithms: - -.. code-block:: python - - import ikomia - - algos = ikomia.ik_registry.get_online_algorithms() - for algo in algos: - name = algo["name"] - -.. note:: - We provide an auto-completion mechanism proposing available algorithms while coding (for built-in and installed algorithms only). Is is available under the **ik** namespace. - - .. figure:: _static/auto_completion.jpg - - Auto completion for algorithms name - - -Create workflow from scratch ------------------------------- - -The sample below show how to instanciate algorithms and connect them in a runnable workflow. - -.. code-block:: python - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - - wf = workflow.create("FromScratch") - - # Instanciate Box Filter algorithm - box_filter_id, box_filter = wf.add_task("ocv_box_filter") - # Or - box_filter_id, box_filter = wf.add_task(ik.ocv_box_filter) - # Connection to the root node (mandatory) - wf.connect_tasks(wf.getRootID(), box_filter_id) - - # Instanciate CLAHE algorithm - clahe_id, clahe = wf.add_task(ik.ocv_clahe) - # Connection with Box filter - wf.connect_tasks(box_filter_id, clahe_id) - - # Set image input of the workflow - img_path = "my_image_folder/my_image.png" - wf.set_image_input(path=img_path) - # Run workflow - wf.run() - -See :py:meth:`~ikomia.dataprocess.workflow.create`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.add_task`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.connect_tasks` and -:py:meth:`~ikomia.dataprocess.workflow.Workflow.run` for details. - - -Save workflow to JSON ---------------------- - -Workflows can be exported in human-readable format (JSON). - -.. code-block:: python - - from ikomia.dataprocess import workflow - - wf = workflow.create("FromScratch") - # Build your workflow here - wf.save("path/to/workflow.json") - -See :py:meth:`~ikomia.dataprocess.workflow.Workflow.save` for details. - - -Load workflow from JSON ------------------------ - -Workflows can be loaded from JSON file. A classic use case is to build your workflow with Ikomia Studio (no code) and export it as JSON. -Then you can simply execute this workflow everywhere with the following code: - -.. code-block:: python - - from ikomia.dataprocess import workflow - - # Load workflow - wf = workflow.load("path/to/workflow.json") - # Set image input of the workflow - img_path = "my_image_folder/my_image.png" - wf.set_image_input(path=img_path) - # Run workflow - wf.run() - -See :py:meth:`~ikomia.dataprocess.workflow.load` for details. - - -Run workflow on common inputs ------------------------------ - -Ikomia API provides features to run workflow on classic image-based inputs. - -.. code-block:: python - - import numpy as np - from ikomia.dataprocess import workflow - - wf = workflow.load("path/to/workflow.json") - - # Run on image from array - img_array = np.random.randint(low=0, high=255, size=(512, 512, 3), dtype=np.uint8) - wf.run_on(array=img_array) - - # Run on image from file path - img_path = "path/to/image.png" - wf.run_on(path=img_path) - - # Run on image from URL - img_url = "http://url/to/image.jpg" - wf.run_on(url=img_url) - - # Run on images from folder - folder_path = "path/to/folder" - wf.run_on(folder=folder_path) - -See :py:meth:`~ikomia.dataprocess.workflow.Workflow.run_on` for details. - - -Set parameters of workflow algorithms -------------------------------------- - -Each algorithm comes with its own set of parameters. From a workflow object instance, you have access to each algorithm with :py:meth:`~ikomia.dataprocess.workflow.Workflow.find_task`. -It returns the task object instance and id from which you can then set parameters. - -.. code-block:: python - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - - # Load workflow - wf = workflow.load("path/to/workflow.json") - # Get specific algorithm of the workflow - box_filter_id, box_filter = wf.find_task(name=ik.ocv_box_filter) - # Set new parameters - new_params = { ik.ocv_box_filter_param.kSizeHeight: 11, ik.ocv_box_filter_param.kSizeWidth: 11 } - wf.set_parameters(new_params, task_id=box_filter_id) - -With name only: - -.. code-block:: python - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - - # Load workflow - wf = workflow.load("path/to/workflow.json") - # Set new parameters - new_params = { ik.ocv_box_filter_param.kSizeHeight: 11, ik.ocv_box_filter_param.kSizeWidth: 11 } - wf.set_parameters(new_params, task_name=ik.ocv_box_filter) - -.. note:: - Like for algorithm names, you can use the **ik** namespace to have auto-completion for parameter names. In the **ik** namespace, - you will find a sub-namespace for each algorithm: *name_of_algorithm_param*. - -.. important:: - The example above assumes that there is only one Box Filter algorithm in the workflow. If it is not the case, you can set a keywords argument **index** in - both :py:meth:`~ikomia.dataprocess.workflow.Workflow.find_task` and :py:meth:`~ikomia.dataprocess.workflow.Workflow.set_parameters`. \ No newline at end of file diff --git a/doc/source/getting_started.md b/doc/source/getting_started.md new file mode 100644 index 00000000..e9b0959d --- /dev/null +++ b/doc/source/getting_started.md @@ -0,0 +1,380 @@ +# Getting Started + +## Installation + +We strongly recommend uding a virtual environment. +If you're not sure where to start, we offer a tutorial [here](bonus/virtual_env). + +### Installing Ikomia API + +Install Ikomia API +```sh +pip install ikomia +``` + +```{warning} +We only support Python 3.7, 3.8, 3.9 and 3.10 on Windows 10 and Linux. +``` + +## Pre-requisites + +Open your favorite IDE (PyCharm, VS Code...) and create a new project in your virtual environment.
+Then, you can just copy/paste the different examples below.
+ +```{important} +If you use a notebook (Jupyter, Jupyter Lab or Google Colab), please copy/paste this code snippet for a better display of images. +``` +```python +from PIL import ImageShow +ImageShow.register(ImageShow.IPythonViewer(), 0) +``` +___ +## Basic usage : workflow with 1 algorithm +___ + +In this example, we simply use the **Canny Edge Detector** from OpenCV.
+ +### Workflow Structure + +```{mermaid} +%%{ + init: { + 'theme': 'base', + 'themeVariables': { + 'primaryBorderColor': '#CC5A20', + 'lineColor': '#CC5A20' + } + } +}%% + graph LR + A[(Input images)] -.-> B(ocv_canny) + B -.-> C[(Output images)] +``` + +### Code + +Create and run your 1st workflow. +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display + +# Init your workflow +wf = Workflow() + +# Add the Canny Edge Detector +canny = wf.add_task(name="ocv_canny", auto_connect=True) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + + +# Inspect your results +display(canny.get_input(0).get_image()) +display(canny.get_output(0).get_image()) +``` +For a step by step explanation, see [here](advanced_guide/index). + +### Results + +Source image | Canny Edge Detector +:-------------------------:|:-------------------------: +![](_static/img_work.jpg) | ![](_static/img_canny.jpg) + +___ +## Basic usage : workflow with 1 algorithm from Ikomia HUB +___ + +In this example, we use an algorithm from Ikomia HUB.
+Just run your workflow and at runtime, it will automagically download and install all algorithms (if not already installed) on your machine. + +### Workflow Structure + +```{mermaid} +%%{ + init: { + 'theme': 'base', + 'themeVariables': { + 'primaryBorderColor': '#CC5A20', + 'lineColor': '#CC5A20' + } + } +}%% + graph LR + A[(Input images)] -.-> B(infer_yolo_v7) + B -.-> C[(Output images)] +``` + +### Code + +Create and run your workflow. +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display + +# Init your workflow +wf = Workflow() + +# Add the YOLO v7 Object Detector +yolov7 = wf.add_task(name="infer_yolo_v7", auto_connect=True) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + +# Inspect your results +display(yolov7.get_input(0).get_image()) +display(yolov7.get_image_with_graphics()) +``` +For a step by step explanation, see [here](advanced_guide/index). + +### Results + +Source image | YOLO v7 Object Detector +:-------------------------:|:-------------------------: +![](_static/img_work.jpg) | ![](_static/img_yolo.jpg) + +___ +## Advanced usage : workflow with 1 algorithm + custom settings +___ + +### Workflow Structure + +```{mermaid} +%%{ + init: { + 'theme': 'base', + 'themeVariables': { + 'primaryBorderColor': '#CC5A20', + 'lineColor': '#CC5A20' + } + } +}%% + graph LR + A[(Input images)] -.-> B(ocv_canny) + B -.-> C[(Output images)] +``` + +### Code + +Adjust the algorithm parameters with our `ik` [auto-completion](advanced_guide/ik_namespace) mechanism ... + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Init your workflow +wf = Workflow() + +# Add the Canny Edge Detector with specific parameters +canny = wf.add_task(ik.ocv_canny(threshold1="100", threshold2="200"), auto_connect=True) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + +# Inspect your results +display(canny.get_input(0).get_image()) +display(canny.get_output(0).get_image()) +``` +... or use a classic Dict approach +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display + +# Init your workflow +wf = Workflow() + +# Add the Canny Edge Detector +canny = wf.add_task(name="ocv_canny", auto_connect=True) + +# Change Canny parameters +canny.set_parameters({ + "threshold1": "100", + "threshold2": "200" +}) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + +# Inspect your results +display(canny.get_input(0).get_image()) +display(canny.get_output(0).get_image()) +``` + +For a step by step explanation, see [here](advanced_guide/index). + +### Results + +Source image | Canny Edge Detector +:---------------------------:|:-------------------------: +![](_static/img_work.jpg) | ![](_static/img_canny_thres.jpg) +___ +## Advanced usage : workflow with 2 algorithms + custom settings +___ + +### Workflow Structure + +```{mermaid} +%%{ + init: { + 'theme': 'base', + 'themeVariables': { + 'primaryBorderColor': '#CC5A20', + 'lineColor': '#CC5A20' + } + } +}%% + graph LR + A[(Input images)] -.-> B(infer_face_detection_kornia) + B --> C(ocv_blur) + C -.-> D[(Output images)] +``` + +### Code + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Init your workflow +wf = Workflow() + +# Add the Kornia Face Detector +face = wf.add_task(ik.infer_face_detection_kornia(), auto_connect=True) + +# Add a blur effect +blur = wf.add_task(ik.ocv_blur(kSizeWidth="61", kSizeHeight="61"), auto_connect=True) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_people.jpg") + +# Inspect your results +display(face.get_image_with_graphics()) +display(blur.get_output(0).get_image()) +``` + +### Results + +Kornia Face Detector | Blurred faces +:-------------------------:|:-------------------------: +![](_static/img_face.jpg) | ![](_static/img_blur.jpg) + +___ +## Advanced usage : export results to JSON +___ + +### Code + +Create and run your workflow. +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik + +# Init your workflow +wf = Workflow() + +# Add the YOLO v7 Object Detector +yolov7 = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + +# Get results as JSON +results_json = yolov7.get_results().to_json(["json_format", "indented"]) +print(results_json) +``` +For a step by step explanation, see [here](advanced_guide/index). + +### Results + +```zsh +{ + "detections": [ + { + "box": { + "height": 235.06271362304688, + "width": 286.51531982421875, + "x": 853.1284790039062, + "y": 374.7386779785156 + }, + "color": { + "a": 9, + "b": 50, + "g": 99, + "r": 232 + }, + "confidence": 0.9322412014007568, + "id": 0, + "label": "laptop" + } + ] +} +``` +___ +## Advanced usage : export workflow to JSON +___ + +### Code + +Create and export your workflow as JSON. +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik + +# Init your workflow +wf = Workflow("My workflow") + +# Add the YOLO v7 Object Detector +yolov7 = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) + +# Save your workflow as JSON in the current folder or specify a path +# wf.save("/path/to/my_workflow.json") +wf.save("./my_workflow.json") +``` + +Then just load and run your workflow. +```python +from ikomia.dataprocess import workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display + +# Load your workflow from the current folder or specify a path +# wf = workflow.load("/path/to/my_workflow.json") +wf = workflow.load("./my_workflow.json") + +# Run on your image +# wf.run_on(path="path/to/your/image.png") +wf.run_on(url="https://raw.githubusercontent.com/Ikomia-dev/notebooks/main/examples/img/img_work.jpg") + +# Find all tasks with the name 'infer_yolo_v7' in the workflow +# and store them in a list +# yolov7_list = wf.find_task("infer_yolo_v7") +yolov7_list = wf.find_task(ik.infer_yolo_v7.name()) +yolov7 = yolov7_list[0] + +# Inspect your results +display(yolov7.get_input(0).get_image()) +display(yolov7.get_image_with_graphics()) + +``` + +For a step by step explanation, see [here](advanced_guide/index). + +### Results + +Source image | YOLO v7 Object Detector +:-------------------------:|:-------------------------: +![](_static/img_work.jpg) | ![](_static/img_yolo.jpg) + +___ +## Conclusion +___ +Congratulations! You've reached the end of the quickstart guide. +You should now have a good understanding of how to use Ikomia API to create, customize and run workflows with various algorithms. +Feel free to explore more features and create your own amazing workflows! diff --git a/doc/source/going_deeper_workflow.rst b/doc/source/going_deeper_workflow.rst deleted file mode 100644 index e9402a0a..00000000 --- a/doc/source/going_deeper_workflow.rst +++ /dev/null @@ -1,333 +0,0 @@ -Going deeper with workflows -=========================== - - -Set workflow inputs -------------------- - -In the previous section, we use :py:meth:`~ikomia.dataprocess.workflow.Workflow.run_on` to execute a workflow on common inputs. -But this function can only be used for a workflow with a single input. In fact, a workflow object is also a task -(:py:mod:`~ikomia.dataprocess.workflow.Workflow` is derived from :py:mod:`~ikomia.core.CWorkflowTask`) and you can add as many inputs as you want. -Please find below the generic way to set workflow inputs. - -.. code-block:: python - - from ikomia.core import IODataType - from ikomia.dataprocess import workflow, CImageIO - - wf = workflow.create("MyWorkflow") - # create image inputs - first_input = CImageIO(IODataType.IMAGE, "1st", "path/to/image1") - second_input = CImageIO(IODataType.IMAGE, "2nd", "path/to/image2") - # add 2 inputs - wf.add_input(first_input) - wf.add_input(second_input) - # Or - wf.set_input(first_input, 0) - wf.set_input(second_input, 1) - -See :py:meth:`~ikomia.dataprocess.workflow.Workflow.add_input` and :py:meth:`~ikomia.dataprocess.workflow.Workflow.set_input` for details. - -The :py:mod:`~ikomia.dataprocess.workflow.Workflow` class also provides helper functions to ease the management of image inputs. You can use -:py:meth:`~ikomia.dataprocess.workflow.Workflow.set_image_input` and :py:meth:`~ikomia.dataprocess.workflow.Workflow.set_directory_input` -for this specific data type. - - -Get a specific workflow task ----------------------------- - -In some cases, it may be necessary to access the task object instance directly. The :py:mod:`~ikomia.dataprocess.workflow.Workflow` class provides -a single method to get a task from its name: :py:meth:`~ikomia.dataprocess.workflow.Workflow.find_task`. When a workflow has several tasks with the -same name, the function returns the list of candidates. Please note that the candidates are sorted according to their order of insertion in the workflow, -from the oldest to the most recent. You can also specify a zero-based index (insertion order) to get the wanted task only. - -Considering the following workflow: - -.. image:: _static/workflow_example1.jpg - -Here is how you will retrieve a specific task: - -.. code-block:: python - - from ikomia.dataprocess import workflow - - wf = workflow.load("path/to/workflow") - # Get the bilateral filter task - bilateral_id, bilateral_obj = wf.find_task("ocv_bilateral_filter") - # Get the candidates for Canny filter - # canny_candidates is a list of pairs (id, obj) here - canny_candidates = wf.find_task("ocv_canny") - # Get the first inserted Canny filter task - first_canny_id, first_canny_obj = wf.find_task("ocv_canny", 0) - # Get the second inserted Canny filter task - second_canny_id, second_canny_obj = wf.find_task("ocv_canny", 1) - -.. note:: - When you create a workflow from scratch, the function :py:meth:`~ikomia.dataprocess.workflow.Workflow.add_task` returns a pair (id, obj) that could be used - to get the task later. In this case, you should call :py:meth:`~ikomia.dataprocess.workflow.Workflow.getTask` with the corresponding id instead of - :py:meth:`~ikomia.dataprocess.workflow.Workflow.find_task` (faster). - - -Get workflow outputs --------------------- - -The generic way to get workflow outputs is to firstly get the task object and then get its outputs. - -.. code-block:: python - - from ikomia.dataprocess import workflow - - wf = workflow.create("ObjectDetection") - # Store id and object instance while adding task to the workflow - yolov4_id, yolov4_obj = wf.add_task("infer_yolo_v4") - wf.connect_tasks(wf.getRootID(), yolov4_id) - - wf.run_on(path="path/to/image.png") - - # Optional use find_task - yolov4_id, yolov4_obj = wf.find_task("infer_yolo_v4") - - # Get outputs - # 1 - Forwarded source image: CImageIO object - img_output = yolov4_obj.get_output(0) - # 2 - Graphics objects (box): CGraphicsOutput object - graphics_output = yolov4_obj.get_output(1) - # 3- Box information: CBlobMeasureIO object - box_output = yolov4_obj.get_output(2) - -The :py:mod:`~ikomia.dataprocess.workflow.Workflow` class provides convenient methods to get outputs by type. For all these methods, -you could get outputs from the task name or the task id (faster). When using task name, the methods will return a list of outputs for all matching -tasks. When a task has several outputs of the same type, you can specify the output index (zero-based index among all outputs). - -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_image_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_graphics_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_numeric_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_data_string_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_blob_measure_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_dataset_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_array_output` -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.get_path_output` - -.. code-block:: python - - from ikomia.dataprocess import workflow - - wf = workflow.create("ObjectDetection") - # Store id and object instance while adding task to the workflow - yolov4_id, yolov4_obj = wf.add_task("infer_yolo_v4") - wf.connect_tasks(wf.get_root_id(), yolov4_id) - - wf.run_on(path="path/to/image.png") - - img_output = wf.get_image_output(yolov4_id) - graphics_output = wf.get_graphics_output(yolov4_id) - box_output = wf.get_blob_measure_output(yolov4_id) - -.. note:: - We provide high-level methods to handle image outputs. Thus from a workflow object, you can access image array directly - (:py:meth:`~ikomia.dataprocess.workflow.Workflow.get_image`) or compute the merge image (for visualization) between graphics and image - outputs (:py:meth:`~ikomia.dataprocess.workflow.Workflow.get_image_with_graphics`). - - -Handle the workflow graph structure ------------------------------------ - -A workflow is a graph where the nodes are the runnable tasks (algorithms) and the links between nodes are connections from task outputs to task inputs. -Basically, you need two methods to build your own workflow: - -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.add_task`: instanciate an algorithm object and add it to the workflow. All algorithms are identified by their unique names and the function uses this name to create instance (factory design pattern). Instanciation process firstly searches for installed algorithms in the registry. If not found, it searches in Ikomia HUB and do all installation steps automatically. Note that this installation can take a while (download package and install dependencies) but it will be executed once. -- :py:meth:`~ikomia.dataprocess.workflow.Workflow.connect_tasks`: connect 2 tasks of the workflow so that output data from the source task will be forwarded to target task input when running the workflow. - -The first way to connect tasks is to let the system create connections automatically based on input and output data types. This will work well in simple scenarios. -In the following example, we will create a simple workflow composed by a Box Filter (noise reduction) and CLAHE algorithm (histogram equalization). Both tasks have -2 inputs (IMAGE + GRAPHICS) and 1 output (IMAGE). In this simple case, auto-connection will work well and make the code easy. - -.. code-block:: python - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - - wf = workflow.create("MyWorkflow") - - # Add Box Filter - box_filter_id, box_filter = wf.add_task(ik.ocv_box_filter) - - # Connect to root (auto-connection) - wf.connect_tasks(wf.get_root_id(), box_filter_id) - - # Add CLAHE - clahe_id, clahe = wf.add_task(ik.ocv_clahe) - - # Connect to Box Filter (auto-connection) - wf.connect_tasks(box_filter_id, clahe_id) - -If you want to have a full control in the connection mechanism, you could set manually the list of connections between 2 tasks. A connection is defined as a pair of index, -the first one being the output index of the source task, the second being the input index of the target task. You must pass a list of pairs because 2 tasks can be connected -by multiple output-input links. Adding a DT Filter with manual connections to the previous workflow will look like this: - -.. code-block:: python - - # Add DT Filter algorithm to the workflow - dtfilter_id, dtfilter = wf.add_task(ik.ocv_dt_filter) - - # Connect to CLAHE with manual connections - wf.connect_tasks(clahe_id, dtfilter_id, [(0, 0), (0, 1)]) - -The :py:mod:`~ikomia.dataprocess.workflow.Workflow` class provides also functions to browse the graph structure of an existing workflow. Consult -:py:meth:`~ikomia.dataprocess.workflow.Workflow.getTaskIDs`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.getTask`, -:py:meth:`~ikomia.dataprocess.workflow.Workflow.getParents`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.getFinalTasks`, -:py:meth:`~ikomia.dataprocess.workflow.Workflow.getInEdges`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.getOutEdges`, -:py:meth:`~ikomia.dataprocess.workflow.Workflow.getEdgeSource`, :py:meth:`~ikomia.dataprocess.workflow.Workflow.getEdgeTarget`, -:py:meth:`~ikomia.dataprocess.workflow.Workflow.getEdgeInfo` for details. - - -Create a Deep Learning training workflow ----------------------------------------- - -Training deep learning models is an important use case of Ikomia API. The workflow approach is also well suited for this case and you can handle it -with few lines of code. Basically, it will consist in 2 main tasks: - -- a dataset loader that will convert your custom dataset structure into the Ikomia Dataset structure. This conversion is mandatory to leverage all training algorithms you can find in Ikomia HUB. We provide dataset loader of common formats like COCO, PascalVOC, YOLO... -- a training algorithm. You will find various algorithms in Ikomia HUB for classification, object detection, segmentation... - -Here is an example of a training workflow for a YOLOv4 model and a custom dataset in YOLO format (grapes detection): - -.. code-block:: python - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - - wf = workflow.create("MyTrainingWorkflow") - - # Add dataset loader for grapes dataset - # No need to connect dataset loader task to root node as it does not need workflow input - wgisd_id, wgisd = wf.add_task("dataset_wgisd") - dataset_params = { - ik.dataset_wgisd_param.data_folder_path: "path/to/data/folder", - ik.dataset_wgisd_param.class_file_path: "path/to/class/file.txt" - } - wf.set_parameters(dataset_params, task_id=wgisd_id) - - # Add YOLO training algorithm - yolo_id, yolo = wf.add_task(ik.train_yolo) - yolo_params = { ik.train_yolo_param.model: "yolov4" } - wf.set_parameters(yolo_params, task_id=yolo_id) - wf.connect_tasks(wgisd_id, yolo_id) - - # Start training - wf.run() - -.. note:: - Ikomia API integrates MLflow and Tensorboard for training monitoring. Depending on the algorithm implementation, - you will have access to metrics, parameters, artifacts in MLflow or Tensorboard or both. - -.. important:: - If you need a model not present in Ikomia HUB, it is quiet easy to port your preferred model in Ikomia ecosystem. - Documentation can be found :doc:`here ` and :doc:`here `. - - -Working with video files ------------------------- - -Processing video files is available out of the box. Ikomia API leverages OpenCV video reader capabilities to apply -any workflows on whole video. Basically, it will execute the workflow on every frames and return when all frames are -processed. You should enable the auto-save mode (:py:meth:`~ikomia.core.pycore.CWorkflowTask.setAutoSave`) at -workflow or task level to save outputs to disk. Output folder can be set at either workflow or task level also -(:py:meth:`~ikomia.core.pycore.CWorkflowTask.set_outputFolder`), default is the user home folder. - -.. code-block:: - - from ikomia.dataprocess import workflow - - wf = workflow.load("path_to_your_workflow") - # Enable auto-save mode to let Ikomia API save outputs to disk for all tasks - wf.set_auto_save(True) - # Video from local filesystem - wf.run_on(path="path_to_your_video.avi") - # Video from public url - wf.run_on(url="url_of_your_video") - # Batch processing from a folder - wf.run_on(folder="local_folder_containing_your_videos") - - -Working with video streams --------------------------- - -At this time, we do not offer high level API to handle streams. On the other hand, it is very simple to -run a workflow on each frame acquired by a third-party video library. Here is an example with OpenCV: - -.. code-block:: - - from ikomia.utils import ik - from ikomia.dataprocess import workflow - import cv2 - - # Initializing stream capture - cap = cv2.VideoCapture(0) - - # Build workflow - wf = workflow.create("MyVideoWorkflow") - clahe_id, clahe = wf.add_task(ik.ocv_clahe) - wf.connect_tasks(wf.getRootID(), clahe_id) - canny_id, canny = wf.add_task(ik.ocv_canny) - wf.connect_tasks(clahe_id, canny_id) - - while True: - ret, img = cap.read() - # Execute on current frame - wf.run_on(array=img) - res_img = wf.get_image(canny_id, 0) - cv2.imshow("Result", res_img) - - if cv2.waitKey(1) == 27: - break - - cv2.destroyAllWindows() - - -Get workflow time metrics -------------------------- - -Ikomia API provides functions to get executing time of a workflow, globally and at task level. - -Get the total time (:py:meth:`~ikomia.dataprocess.workflow.Workflow.getTotalElapsedTime`): - -.. code-block:: - - from ikomia.dataprocess import workflow - - wf = workflow.load("path/to/workflow.json") - wf.set_image_input(path="path/to/image.png") - wf.run() - - # Executing time in ms - time_ms = wf.get_total_elapsed_time() - -Get executing time for each task -(:py:meth:`~ikomia.core.pycore.CWorkflowTask.get_elapsed_time` and -:py:meth:`~ikomia.dataprocess.workflow.Workflow.get_elapsed_timeTo`): - -.. code-block:: - - from ikomia.dataprocess import workflow - - wf = workflow.load("path/to/workflow.json") - wf.set_image_input(path="path/to/image.png") - wf.run() - - ids = wf.getTaskIDs() - for task_id in ids: - task = wf.get_task(task_id) - time_ms = task.get_elapsed_time() - time_to_ms = wf.get_elapsed_time_to(task_id) - -You can also get all metrics in a dict structure (:py:meth:`~ikomia.dataprocess.workflow.Workflow.get_time_metrics`): - -.. code-block:: - - from ikomia.dataprocess import workflow - - wf = workflow.load("path/to/workflow.json") - wf.set_image_input(path="path/to/image.png") - wf.run() - metrics = wf.get_time_metrics() diff --git a/doc/source/hello_world_plugin.rst b/doc/source/hello_world_plugin.rst deleted file mode 100644 index 2f7f03c5..00000000 --- a/doc/source/hello_world_plugin.rst +++ /dev/null @@ -1,111 +0,0 @@ -Hello world plugin -================== - -In this first tutorial, we will create an empty plugin and introduce the core mechanisms. -Basically, first steps of plugin creation can be done either manually or with our dedicated module. - - -With Ikomia Plugin Manager (recommended) ----------------------------------------- - -The simplest way to create plugins is to use the integrated Plugin Manager: - -.. image:: _static/plugin_manager.jpg - -The left table shows the list of all your plugins, you will find a list of action buttons to its right. -Click on the first button to start creating a plugin: - -.. image:: _static/new_plugin.jpg - -Set parameters: - -- *Plugin name*: must be **unique** as it is the identifier of the plugin. The given name will appear in the Ikomia process library. -- *Process type*: rely on the source data type. This choice determines the base class on which the process class will be derived from: - - - *Generic process*: no input/output and no data structure pre-defined. See :py:class:`~ikomia.core.pycore.CWorkflowTask`. - - *Image process*: image processing plugin. - - - inputs: image + graphics layer - - ouputs: image - - See :py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask`. - - - *Interactive image process*: image processing plugin with user interation capability. Same inputs/outputs as image process option. See :py:class:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask`. - - *Video process*: video processing plugin. - - - inputs: video + graphics layer - - ouputs: video - - See :py:class:`~ikomia.dataprocess.pydataprocess.CVideoTask`. - - - *Optical flow process*: video processing plugin dedicated to Optical Flow. Same inputs/outputs as video process option. See :py:class:`~ikomia.dataprocess.pydataprocess.CVideoOFTask`. -- *Widget type*: empty widget only (for instance). User must create his own widget according to algorithm parameters. Basic knowledge of Qt framework is recommended. See :py:class:`~ikomia.core.pycore.CWorkflowTaskWidget`. -- *GUI framework*: Qt based Python framework. PyQt5 recommended. - -Click on **Generate** button. - -Your plugin is now **created** and **ready to use**. It is automatically loaded and you can access it from the process library of Ikomia. -At this point, the plugin can be added to any workflow but does nothing. - -The minimal structure of a plugin is composed by these files: - -- *__init__.py*: Python regular package -- :doc:`hello_world.py `: implementation of plugin interface. See :py:class:`~ikomia.dataprocess.pydataprocess.CPluginProcessInterface`. -- :doc:`hello_world_process.py `: implementation of the algorithm, its parameters, its metadata and the factory to create process instance. -- :doc:`hello_world_widget.py `: implementation of the widget and the factory to create an instance. - -.. note:: the code generated by the Plugin Manager is self documented and will guide you through all the required step. - - -With you prefered Python IDE ----------------------------- - -Because an Ikomia plugin is a regular Python package, you can create it from scratch with the IDE of your choice. - -Here are the steps you should follow: - -1. Create a new folder into our dedicated folder with the name of your plugin - Windows - - .. code-block:: bash - - mkdir c:\Users\{username}\Ikomia\Plugins\Python\hello_world - - Linux - - .. code-block:: bash - - mkdir ~/Ikomia/Plugins/Python/hello_world - -2. Create your project (optional) - -3. Choose the Ikomia Python interpreter (optional). Ikomia Python interpreter is located in: - - Windows - - .. code-block:: bash - - c:\Users\{username}\Ikomia\Python\ - - Linux - - .. code-block:: bash - - ~/Ikomia/Python/ - -4. Create the 4 required Python files from your IDE - - *__init__.py* - - *hello_world.py* - - *hello_world_process.py* - - *hello_world_widget.py* - - .. note:: The naming scheme of these files is very important: see the section :doc:`naming convention ` for details. - -4. Implement the plugin interface that will allow your plugin to be loaded in Ikomia. See example :doc:`hello_world.py `. - -5. Implement your process. See example :doc:`hello_world_process.py `. - -6. Implement your widget. See example :doc:`hello_world_widget.py `. - - -That's it. Launch Ikomia, your plugin will be loaded automatically. diff --git a/doc/source/hello_world_plugin_interface.rst b/doc/source/hello_world_plugin_interface.rst deleted file mode 100644 index 212b2ca4..00000000 --- a/doc/source/hello_world_plugin_interface.rst +++ /dev/null @@ -1,28 +0,0 @@ -Plugin interface -================== - -Code example for hello_world plugin interface. - -.. code-block:: python - - from ikomia import dataprocess - - - # -------------------- - # - Interface class to integrate the process with Ikomia application - # - Inherits CPluginProcessInterface from Ikomia API - # -------------------- - class IkomiaPlugin(dataprocess.CPluginProcessInterface): - - def __init__(self): - dataprocess.CPluginProcessInterface.__init__(self) - - def getProcessFactory(self): - # Instantiate process object - from hello_world.hello_world_process import HelloWorldFactory - return HelloWorldFactory() - - def getWidgetFactory(self): - # Instantiate associated widget object - from hello_world.hello_world_widget import HelloWorldWidgetFactory - return HelloWorldWidgetFactory() \ No newline at end of file diff --git a/doc/source/hello_world_plugin_process.rst b/doc/source/hello_world_plugin_process.rst deleted file mode 100644 index a734eb80..00000000 --- a/doc/source/hello_world_plugin_process.rst +++ /dev/null @@ -1,110 +0,0 @@ -Process -======= - -Code example for process implementation - -.. code-block:: python - - from ikomia import core, dataprocess - import copy - # Your imports below - - # -------------------- - # - Class to handle the process parameters - # - Inherits CProtocolTaskParam from Ikomia API - # -------------------- - class HelloWorldParam(core.CWorkflowTaskParam): - - def __init__(self): - core.CWorkflowTaskParam.__init__(self) - # Place default value initialization here - # Example : self.windowSize = 25 - - def set_values(self, paramMap): - # Set parameters values from Ikomia application - # Parameters values are stored as string and accessible like a python dict - # Example : self.windowSize = int(paramMap["windowSize"]) - pass - - def get_values(self): - # Send parameters values to Ikomia application - # Create the specific dict structure (string container) - paramMap = {} - # Example : paramMap["windowSize"] = str(self.windowSize) - return paramMap - - - # -------------------- - # - Class which implements the process - # - Inherits CProtocolTask or derived from Ikomia API - # -------------------- - class HelloWorld(dataprocess.C2dImageTask): - - def __init__(self, name, param): - dataprocess.C2dImageTask.__init__(self, name) - # Add input/output of the process here - # Example : self.add_input(core.CImageProcessIO()) - # self.add_output(core.CImageProcessIO()) - - #Create parameters class - if param is None: - self.set_param_object(HelloWorldParam()) - else: - self.set_param_object(copy.deepcopy(param)) - - def get_progress_steps(self): - # Function returning the number of progress steps for this process - # This is handled by the main progress bar of Ikomia application - return 1 - - def run(self): - # Core function of your process - # Call begin_task_run for initialization - self.begin_task_run() - - # Examples : - # Get input : - # input = self.get_input(indexOfInput) - - # Get output : - # output = self.get_output(indexOfOutput) - - # Get parameters : - # param = self.get_parameters() - - # Get image from input/output (numpy array): - # srcImage = input.getImage() - - # Call to the process main routine - # dstImage = ... - - # Set image of input/output (numpy array): - # output.setImage(dstImage) - - # Step progress bar: - self.emit_step_progress() - - # Call end_task_run to finalize process - self.end_task_run() - - - # -------------------- - # - Factory class to build process object - # - Inherits CTaskFactory from Ikomia API - # -------------------- - class HelloWorldFactory(dataprocess.CTaskFactory): - - def __init__(self): - dataprocess.CTaskFactory.__init__(self) - # Set process information as string here - self.info.name = "hello_world" - self.info.description = "your description" - self.info.authors = "Plugin authors" - # relative path -> as displayed in Ikomia application process tree - self.info.path = "Plugins/Python" - # self.info.iconPath = "your path to a specific icon" - # self.info.keywords = "your keywords" -> for search - - def create(self, param=None): - # Create process object - return HelloWorld(self.info.name, param) diff --git a/doc/source/hello_world_plugin_widget.rst b/doc/source/hello_world_plugin_widget.rst deleted file mode 100644 index 868aac73..00000000 --- a/doc/source/hello_world_plugin_widget.rst +++ /dev/null @@ -1,60 +0,0 @@ -Widget -====== - -Code example for widget implementation - -.. code-block:: python - - from ikomia import core, dataprocess - from ikomia.utils import qtconversion - from hello_world.hello_world_process import HelloWorldParam - #PyQt GUI framework - from PyQt5.QtWidgets import * - - - # -------------------- - # - Class which implements widget associated with the process - # - Inherits CProtocolTaskWidget from Ikomia API - # -------------------- - class HelloWorldWidget(core.CWorkflowTaskWidget): - - def __init__(self, param, parent): - core.CWorkflowTaskWidget.__init__(self, parent) - - if param is None: - self.parameters = HelloWorldParam() - else: - self.parameters = param - - # Create layout : QGridLayout by default - self.gridLayout = QGridLayout() - # PyQt -> Qt wrapping - layoutPtr = qtconversion.PyQtToQt(self.gridLayout) - - # Set widget layout - self.setLayout(layoutPtr) - - def onApply(self): - # Apply button clicked slot - - # Get parameters from widget - # Example : self.parameters.windowSize = self.spinWindowSize.value() - - # Send signal to launch the process - self.emitApply(self.parameters) - - - #-------------------- - #- Factory class to build process widget object - #- Inherits CWidgetFactory from Ikomia API - #-------------------- - class HelloWorldWidgetFactory(dataprocess.CWidgetFactory): - - def __init__(self): - dataprocess.CWidgetFactory.__init__(self) - # Set the name of the process -> it must be the same as the one declared in the process factory class - self.name = "hello_world" - - def create(self, param): - # Create widget object - return HelloWorldWidget(param, None) diff --git a/doc/source/index.md b/doc/source/index.md new file mode 100644 index 00000000..e5a3c7c2 --- /dev/null +++ b/doc/source/index.md @@ -0,0 +1,99 @@ +# Ikomia API Documentation + + +
+ + Logo + +

Your end to end open source API to prototype Computer Vision solutions

+
+
+

+ + Stars + + + Website + + + Python + + + Python + + + GitHub + + + GitHub tags + +
+ + Slack community + +

+ +

+ + + +

+ + +```{toctree} +:hidden: + +getting_started +``` + +```{toctree} +:caption: Advanced Ikomia Guide +:hidden: + +advanced_guide/index +``` + +```{toctree} +:caption: Tutorials +:hidden: + +tutorials/how_to_on_stream +object_detection/index +``` + +```{toctree} +:caption: Bonus +:hidden: + +bonus/virtual_env +``` + +```{toctree} +:caption: Development +:hidden: + +modules +release_notes/index +``` + + +## About The Project + +Ikomia API is an **open source dev tool** designed to simplify the development and deployment of Computer Vision solutions. +It enables effortless integration of state-of-the-art algorithms from multiple sources, such as **OpenCV**, **Detectron2**, **OpenMMLab**, and **YOLO**, into your projects. + +With Ikomia API, you can focus on building powerful and innovative Computer Vision applications without worrying about the complexities of managing dependencies and integrating different frameworks. +The API handles the download, installation and management of the selected algorithms, enabling the creation of customized solutions with minimal coding effort. + +Whether you're a seasoned developer or new to the field of Computer Vision, Ikomia API provides an accessible and efficient way to stay up-to-date with the latest advancements and bring your ideas to life. + +## Key Features + +- **Ease of use**: Quickly integrate state-of-the-art Computer Vision algorithms into your projects with just a few lines of code. +- **Cross-platform**: Compatible with Windows and Linux operating systems. +- **Support for popular frameworks**: Seamlessly use popular frameworks like OpenCV, Detectron2, OpenMMLab, and YOLO. +- **Automatic dependency management**: Ikomia API automatically downloads, installs, and manages the requirements for the chosen algorithms. +- **Modular design**: Easily mix and match algorithms from different repositories to create custom solutions. +- **Open source**: Benefit from the collaborative development and transparency of an open source project. +- **Community**: Join the Slack community to get support, share ideas, and collaborate with other developers. +- **Regular updates**: Stay up-to-date with the latest Computer Vision advancements through frequent releases and updates. \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 1fcf1db4..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,64 +0,0 @@ -Welcome to Ikomia API documentation -=================================== - -:Current version: |version| - -The Ikomia platform is made up of three components: - - - **Ikomia HUB**: HUB is the central sharing place for Plug'n'Play algorithms in Computer Vision and Deep Learning. We regularly push the best state of the art algorithms in classification, object detection, segmentation or pose estimation (among others). With Ikomia HUB, all algorithms are Open Source and ready to use in few clicks and you can easily edit the code if you want. - - **Ikomia Studio**: Studio is an Open Source no-code application (Linux and Windows) that allows you to test, chain and train any Computer Vision algorithms with a drag and drop system. You can load all images and video formats, and select the best state of the art algorithms from Ikomia HUB. - - **Ikomia API**: Python API to leverage state of the art algorithms for your own computer vision application and/or create plugins for Ikomia Studio and Ikomia HUB. - - -.. note:: Ikomia API is built around Ikomia Core, a set of C++ libraries with Python bindings. - - -.. important:: Ikomia Studio and Ikomia API are Open-Source projects, distributed under AGPLv3 and Apache 2.0 respectively. - - -Choose your API usage ---------------------- -As an Ikomia user, you will be led to use this API for two reasons: - - - **Create workflows and use Ikomia algorithms in your custom application**: leverage built-in algorithms and those from Ikomia HUB directly in your application. Run single algorithm or workflows with few lines of code. - - **Create plugins for Ikomia platform**: with a little wrap around your Python code, you are able to give access to your algorithm from a user friendly software (Ikomia Studio) and a flexible workflow API. Moreover, from Ikomia Studio you can publish your work to Ikomia HUB in one click and share it with the community. - - -**Ready to start?** - -.. toctree:: - :maxdepth: 1 - - index_api - index_plugin - - -Useful links ------------- - -`Ikomia GitHub repository `_ - -`Ikomia HUB algorithms GitHub repository `_ - -`Ikomia blog `_ - -`Ikomia web site `_ - - -API Reference -------------- -This section provides the auto-generated documentation from the Python code. You will find all the implementation details and -the comprehensive list of available functions. - -.. toctree:: - :maxdepth: 2 - - modules - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/index_api.rst b/doc/source/index_api.rst deleted file mode 100644 index c0b5831f..00000000 --- a/doc/source/index_api.rst +++ /dev/null @@ -1,120 +0,0 @@ -Implement Computer Vision workflows for your application -======================================================== - -This part of the Ikomia API aims to leverage algorithms coming from Ikomia HUB into standalone application. It provides a simple and fast way to -integrate state of the art methods to your image analysis pipeline. Ikomia API is framework-agnostic, algorithms can be implemented in your favorite -Python library (PyTorch, TensorFlow, Scikit-image ...). - -.. note:: - If you are interested in integrating your own algorithm in Ikomia, please consult :doc:`this documentation `. - - -Registration (free) -------------------- - -Leverage state of the art algorithms from Ikomia HUB is one of the big advantage of using Ikomia API. Then you will need a free Ikomia account so that -you will be able to authenticate while using Ikomia API. If we don't have the chance yet to count you among our users, we invite you to -`register here `_. - - -Installation ------------- - -You simply install Ikomia API via pip for Linux and Windows: - -.. code-block:: zsh - - pip install ikomia - -Another version is also available which provides a GPU-enabled version of OpenCV (CUDA 11, CuDNN 8). This version gives -you access to OpenCV algorithms with GPU acceleration, especially the Deep Learning inference framework. - -.. code-block:: zsh - - pip install ikomia==0.8.0+cu11 -f https://packages.ikomia.com/ikomia/index.html - -.. note:: - For this version, we provide Python wheels for Python 3.7, 3.8 and 3.9. It includes OpenCV package (v4.5.2). For GPU - acceleration with your favorite framework (PyTorch, TensorFlow...), you must have installed CUDA 11 drivers for your - graphic card and the GPU-enabled version of this framework. - - For Linux users, the wheel targets the platform manylinux2014 so that it should be compatible with most of recent - distributions. - - For Windows, the wheel is only compatible with Windows 10. - - -.. Important:: - **OpenCV** - - A version of OpenCV with specific options is bundled within the Ikomia package. It includes all the core - and contribution librairies. There is only one important constraint to respect, **you must import Ikomia - module before importing cv2 module**. As a result, the package *opencv-python* or *opencv-python-headless* from Pypi repository should not be installed in - the same Python environment. This may lead to incompatibility issues. - - -Concepts --------- - -Workflow -^^^^^^^^ - -This is the core concept to leverage algorithms in your application. It consists in a graph-based structure that allows to build complex -scenario by connecting tasks (ie algorithms) through inputs and outputs. Workflow can either be created from scratch or loading from file -exported by the workflow editor of Ikomia Studio. In the second case, no code is needed, you just have to build your workflow graphically, -evaluate it on your data and export it when you are done. - -The Python class :py:mod:`~ikomia.dataprocess.workflow.Workflow` is based on a C++ implementation to ensure performance. - -.. figure:: _static/workflow_editor.jpg - - Ikomia Studio workflow editor - - -Registry -^^^^^^^^ - -The registry module ensures the algorithm management in the Ikomia platform. The module manages operations like download, installation, update -and instanciation. All algorithms are uniquely identified by their name. So you will handle tasks primarly by their names while implementing -your workflow. When importing the Python ikomia module, you will have acces to the global Ikomia registry -(:py:mod:`~ikomia.dataprocess.registry.IkomiaRegistry`). - - - -Task -^^^^ - -A task represents the implementation of a specific algorithm. The common usage of the task object is to insert it in a workflow as a node and connect -it to others tasks. But a task is also a standalone object that can be executed independently. In Ikomia platform, a task implementation has to -follow a specific architecture (plugin mechanism) as described in :doc:`this section `. This API provides high level functions to -facilitate the use of Ikomia tasks (:py:mod:`~ikomia.core.task`). - - -Inputs and outputs -^^^^^^^^^^^^^^^^^^ - -Every task comes with a list of inputs and outputs. Tasks are connected within a workflow thanks to their inputs/outputs. Ikomia workflow -is designed to deal with almost any algorithm based on image. So depending of the algorithm, you will have to deal with several types of -inputs/outputs. This API provides a comprehensive list of I/O types to address common needs in Computer Vision. You will find more -information :doc:`here `. - - -Authentication --------------- - -Access to Ikomia HUB is reserved for registered users. So if you need algorithms from HUB in your workflow, you have -to set your Ikomia credentials in environment variables: **IKOMIA_USER** and **IKOMIA_PWD**. - - -In practice ------------ - -Let's dive now into the API with practical examples: - -.. toctree:: - :maxdepth: 1 - - first_steps_workflow - going_deeper_workflow - working_with_task - display_tools diff --git a/doc/source/index_plugin.rst b/doc/source/index_plugin.rst deleted file mode 100644 index 8a313950..00000000 --- a/doc/source/index_plugin.rst +++ /dev/null @@ -1,87 +0,0 @@ -Create your algorithm for Ikomia platform -========================================= - -Ikomia platform is an Open Source ecosystem providing plug'n'play algorithms in Computer Vision. Such algorithms can then be tested and evaluated in -Ikomia Studio for fast prototyping. Ikomia Studio is a desktop software (Qt based) that will help you to access and evaluate state of the art algorithms -in a no-code way. It includes built-in algorithms from well-known libraries like **OpenCV** and give access to Ikomia HUB. Ikomia Studio offers -the possibility to build complex **workflows** thanks to a flexible graph-based editor. - -The aim of this API is to offer a simple Python interface to add user-defined plugin into Ikomia platform. A plugin is a Python implementation of an -algorithm executed on image based data. Once implemented, you will be able to handle your plugin like all other algorithms and use it in workflows. -You will also be able to publish it to the Ikomia HUB and promote your work towards Ikomia community. - -The plugin structure --------------------- - -In Ikomia platform, each plugin is intended for use in workflows to process image-based data. A workflow is thus composed of several connected tasks that get inputs, -process them and give results through outputs. When you create your own plugin, there are some few essential components to deal with, each one being implemented by a specific class: - - - **Task**: algorithm implementation, inherited from :py:mod:`~ikomia.core.pycore.CWorkflowTask`. - - **Parameters**: to setup the algorithm, inherited from :py:mod:`~ikomia.core.pycore.CWorkflowTaskParam`. - - **Inputs**: required input data, inherited from :py:mod:`~ikomia.core.pycore.CWorkflowTaskIO`. - - **Outputs**: produced output data, inherited from :py:mod:`~ikomia.core.pycore.CWorkflowTaskIO`. - - **Widget**: user interaction interface (to adjust parameters for example), inherited from :py:mod:`~ikomia.core.pycore.CWorkflowTaskWidget`. - - -Then, each plugin must follow the connection mechanism of Ikomia Studio by providing three classes: - - - **Task factory**: create task object. It also stores all information relative to the algorithm (unique name, description, icon, authors, articles, keywords...). Inherited from :py:mod:`~ikomia.dataprocess.pydataprocess.CTaskFactory`. - - **Widget factory**: create widget object. It must set the same unique name as the task factory. Inherited from :py:mod:`~ikomia.dataprocess.pydataprocess.CWidgetFactory`. - - **Main plugin interface**: allow to get the two factories described above. Inherited from :py:mod:`~ikomia.dataprocess.pydataprocess.CPluginProcessInterface`. - - -Finally, the minimal file structure of a plugin could be: - - - my_plugin_name (folder) - - - __init__.py - - my_plugin_name.py: implementation of the main plugin interface. - - my_plugin_name_process.py: implementation of the algorithm, its parameters and its factory. - - my_plugin_name_widget.py: implementation of the widget and its factory. - - -Getting started ---------------- - -You are almost ready to write your first Ikomia plugin. We just need to introduce how the Python environment is managed in Ikomia Studio. -As a C++/Qt software, Ikomia Studio embeds a specific version of the Python interpreter. -So you need to use this environment while implementing your plugin. More details are given in the following pages: - -.. toctree:: - :maxdepth: 1 - - python_env - dependencies - naming - - -These tutorial sections will help you understand the API structure and will guide you through the creation of your first plugins: - -.. toctree:: - :maxdepth: 1 - - hello_world_plugin - opencv_plugin - interactive_plugin - - -Going deeper ------------- - -.. toctree:: - :maxdepth: 1 - - plugin_parameters - plugin_task - plugin_io - - -Examples --------- - -Here are source codes associated with the tutorials. - -.. toctree:: - :maxdepth: 2 - - examples \ No newline at end of file diff --git a/doc/source/integration/index.md b/doc/source/integration/index.md new file mode 100644 index 00000000..d0c71575 --- /dev/null +++ b/doc/source/integration/index.md @@ -0,0 +1,173 @@ +# How to create and integrate your algorithm in workflows + +```{toctree} +:hidden: + +dependencies +naming +``` + +```{toctree} +:caption: Examples +:hidden: + +hello_world_plugin +opencv_plugin +interactive_plugin +``` + +Creating and integrating your own algorithms into workflows can be a powerful way to automate and streamline your data processing tasks. +While there are many pre-existing algorithms available, there may be times when you need to develop your own algorithm to meet specific requirements. +Fortunately, there are tools available, such as the Ikomia API, that can help simplify the process of creating and integrating your own algorithms. + +In this document, we will provide an overview of the steps involved in creating and integrating your own algorithm into a workflow using the Ikomia API. +We will cover topics such as the structure of an algorithm file, tips for editing algorithms, and how to integrate your algorithm into a workflow. +We will also provide examples of different types of algorithms that can be created and integrated into workflows. + +## Algorithm creation with `ikomia-cli` + +The Ikomia API provides a command-line interface tool called `ikomia-cli` that can be used to create a new algorithm. Here's how to get started: + +1. First, make sure you have the `ikomia-cli` tool installed. You can do this by running the following command in your terminal: +```shell +pip install ikomia-cli +``` +2. Once you have installed `ikomia-cli`, you can create a new algorithm by running the following command: +```shell +ikcli algo create my_first_algo +``` +This will create a new directory called "my_first_algo" in "~/Ikomia/Plugins/Python/" directory. Inside this directory, you will find several files that make up your algorithm. + +3. The main file of your algorithm is "my_first_algo_process.py". This file contains the Python code that implements your algorithm. You can open this file in a text editor or IDE to begin editing it. +4. The "my_first_algo_process.py" file is structured using the Ikomia API's `DataProcess` class. This class provides a standard structure for algorithms and makes it easy to define inputs, outputs, and other properties of your algorithm. Here's an example of what your "my_first_algo_process.py" file might look like: +```python +from ikomia import core, dataprocess +import copy + +class MyFirstAlgo(core.CWorkflowTask): + + def __init__(self, name, param): + core.CWorkflowTask.__init__(self, name) + + # Define your inputs and outputs here + self.add_input(dataprocess.CImageIO()) + self.add_output(dataprocess.CImageIO()) + + # Create parameters class + if param is None: + self.set_param_object(MyFirstAlgoParam()) + else: + self.set_param_object(copy.deepcopy(param)) + + def run(self): + # Implement your algorithm here + input_img = self.get_input(0) + output_img = input_img.clone() + self.get_output(0).set_image(output_img) +``` +In this example, we are defining an algorithm called MyFirstAlgo. +This algorithm has one input and one output, both of which are images (CImageIO). +In the run method, we implement our algorithm by reading in the input image, making a copy of it, and then setting the output image to be the copy. + +Note that you can customize your algorithm's inputs and outputs to fit your specific use case. For example, if your algorithm requires text inputs or outputs, you could use CTextIO instead. + +5. Once you have defined your algorithm in the "my_first_algo.py" file, you can save the file and exit your text editor or IDE. +Your algorithm is now ready to be integrated into a workflow. + +That's it! With just a few simple steps, you can create your own algorithm using the Ikomia API and `ikomia-cli`. + +## Algorithm integration + +Once you have created and edited your algorithm, you can integrate it into a larger workflow using the Ikomia API. +Here are the basic steps for integrating your algorithm: + +1. Import the necessary modules from the Ikomia API: +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display +``` +2. Create a new workflow object: +```python +wf = Workflow() +``` +3. Add your algorithm to the workflow: +```python +my_algorithm = wf.add_task(ik.my_first_algo(), auto_connect=True) +``` +4. Connect the inputs and outputs of your algorithm to other tasks in the workflow as needed. This can be done using the `auto_connect=True` argument when adding your algorithm to the workflow, or by manually connecting inputs and outputs using the `connect_tasks()` method. +5. Run the workflow on your input data: +```python +wf.run_on(path="/path/to/input") +``` +6. Retrieve the output of your algorithm and display it: +```python +output_data = my_algorithm.get_output(0).get_image() +display(output_data) +``` +The full code: +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Init the workflow +wf = Workflow() + +# Add your algorithm +my_algorithm = wf.add_task(ik.my_first_algo(), auto_connect=True) + +# Run on your image +wf.run_on(path="/path/to/image.png") + +# Inspect your results +output_data = my_algorithm.get_output(0).get_image() +display(output_data) +``` +By following these steps, you can easily integrate your algorithm into a larger workflow and process your data with other algorithms. You can also use the Ikomia STUDIO to create and visualize your workflow, and save your workflows for later use. + +[comment]: <> (### Graphics) + +[comment]: <> (Graphics represent all vectorial items (line, polygon, text...) that ) + +[comment]: <> (bring additionnal information to images. They can be stored as input ({py:mod}`~ikomia.dataprocess.pydataprocess.CGraphicsInput`) ) + +[comment]: <> (or output {py:mod}`~ikomia.dataprocess.pydataprocess.CGraphicsOutput`). Different types of graphics ) + +[comment]: <> (are provided, each one being implemented in a dedicated class:) + +[comment]: <> (- Point: {py:mod}`~ikomia.core.pycore.CGraphicsPoint`) + +[comment]: <> (- Polyline: {py:mod}`~ikomia.core.pycore.CGraphicsPolyline`) + +[comment]: <> (- Rectangle/Square: {py:mod}`~ikomia.core.pycore.CGraphicsRectangle`) + +[comment]: <> (- Ellipse/Circle: {py:mod}`~ikomia.core.pycore.CGraphicsEllipse`) + +[comment]: <> (- Polygon: {py:mod}`~ikomia.core.pycore.CGraphicsPolygon`) + +[comment]: <> (- Polygon with hole(s): {py:mod}`~ikomia.core.pycore.CGraphicsComplexPolygon`) + +[comment]: <> (- Text: {py:mod}`~ikomia.core.pycore.CGraphicsText`) + +[comment]: <> (You can access to every graphics with :) + +[comment]: <> (```python) + +[comment]: <> (obj_list = output_obj.get_items()) + +[comment]: <> (```) + +[comment]: <> ({py:meth}`~ikomia.dataprocess.pydataprocess.CGraphicsOutput.get_items` returns a list of graphical objects so you can iterate on it. ) + +[comment]: <> (When you have a {py:mod}`~ikomia.dataprocess.pydataprocess.CImageIO` and a {py:mod}`~ikomia.dataprocess.pydataprocess.CGraphicsOutput` as outputs, you can easily burn graphics on your image with {py:func}`~ikomia.dataprocess.pydataprocess.CImageIO.get_image_with_graphics`) + +[comment]: <> (```python) + +[comment]: <> (from ikomia.utils.displayIO import display) + +[comment]: <> (img = yolov7.get_image_with_graphics()) + +[comment]: <> (display(img)) + +[comment]: <> (```) \ No newline at end of file diff --git a/doc/source/interactive_plugin.rst b/doc/source/interactive_plugin.rst deleted file mode 100644 index 27fabff7..00000000 --- a/doc/source/interactive_plugin.rst +++ /dev/null @@ -1,547 +0,0 @@ -Interactive plugin -================== - -In this tutorial, we will see how to implement a plugin managing user interaction through graphics objects input. -We will illustrate this through the implementation of active contour algorithms from scikit-image library : - -- `morphological_geodesic_active_contour `_ -- `morphological_chan_vese `_ - -Active contour algorithms, also called «snakes», are segmentation methods matching a deformable model to an image region by means -of energy minimization. They require initial regions or seeds in the form of a binary mask from which an iterative update strategy -will be applied (growth or shrinkage). Initial binary mask can be either the result of a previous task in workflow or manual -shapes drawn by users (Ikomia graphics objects). - -Here are the steps we will follow: - -- Define required inputs and outputs -- Get initial contour from user graphics input or binary mask directly -- Call active contour method -- Generate results - -We skip here all steps to create a new empty plugin. -Please refer to :doc:`Hello World tutorial ` if you are not familiar with it. - -**Table of contents** - -| :ref:`files_structure` -| :ref:`dependencies` -| :ref:`interface_implementation` -| :ref:`process_implementation` -| :ref:`inputs` -| :ref:`Outputs` -| :ref:`active_contour_methods` -| :ref:`results` -| :ref:`progress_bar` -| :ref:`process_parameters` -| :ref:`process_widget` -| :ref:`process_metadata` -| :ref:`source_code` - - -.. _files_structure: - -Plugin files structure ----------------------- - -- skimage_morpho_snakes - - - __init__.py - - requirements.txt - - skimage_morpho_snakes.py - - skimage_morpho_snakes_process.py - - skimage_morpho_snakes_widget.py - -.. _dependencies: - -Dependencies ------------- - -- OpenCV: basic image operations (built-in in Ikomia software) -- scikit-image: active contour algorithms - -Plugin dependencies are listed in *requirements.txt* so that they will be automatically installed by Ikomia software -during plugin installation. More information about dependency management :doc:`here `. - -.. _interface_implementation: - -Interface implementation ------------------------- - -No features added from the default implementation. -See `skimage_morpho_snakes.py `_. - -.. _process_implementation: - -Process implementation ----------------------- - -Import statements in *skimage_morpho_snakes_process.py*: - -.. code-block:: python - - from ikomia import core, dataprocess - import copy - # your imports below - import cv2 - from skimage.segmentation import (morphological_geodesic_active_contour, inverse_gaussian_gradient, morphological_chan_vese) - from skimage import img_as_float - import numpy as np - -.. _inputs: - -Inputs -^^^^^^ - -Our active contour methods are designed to process 2D images, the corresponding base class from which our -scikit_MorphoSnakesProcess class inherits is :py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask`. It comes with built-in inputs : - -- Source image (:py:class:`~ikomia.dataprocess.pydataprocess.CImageIO`) -- Graphics (:py:class:`~ikomia.dataprocess.pydataprocess.CGraphicsInput`) - -As we discuss earlier, seeds for active contour methods can be set from graphics (user input) or binary mask directly. -So we need to add a new image-based input of type :py:class:`~ikomia.dataprocess.pydataprocess.CImageIO` to handle binary mask initialization. - -.. code-block:: python - - class MorphoSnakes(dataprocess.C2dImageTask): - - def __init__(self, name, param): - dataprocess.C2dImageTask.__init__(self, name) - ... - # add input -> initial level set - self.add_input(dataprocess.CImageIO()) - ... - -.. _outputs: - -Outputs -^^^^^^^ -Here are outputs that our plugin should returned: - -- Final level set as binary mask representing segmented objects (:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask`): directly consummable by connected tasks in workflow. -- Image with overlay containing segmented objects displayed on top of the original image (:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask`): for visualization purpose. - -:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask`-based class comes also with built-in output: - -- Image (:py:class:`~ikomia.dataprocess.pydataprocess.CImageIO`) - -So we need to add a new image-based output of type :py:class:`~ikomia.dataprocess.pydataprocess.CImageIO`. - -.. code-block:: python - - class MorphoSnakes(dataprocess.C2dImageTask): - - def __init__(self, name, param): - dataprocess.C2dImageTask.__init__(self, name) - ... - # add output -> results image - self.add_output(dataprocess.CImageIO()) - ... - -.. _active_contour_methods: - -Active contour methods -^^^^^^^^^^^^^^^^^^^^^^ - -First, we should check the input type the user gives us for the initial level set. -User can give us 2 types of input to define initial contour: - -- Binary mask -- Graphics objects - -If both of them are given, we have to make an arbitrary choice, so we will process the binary image first. -Otherwise we will process graphics input. Let’s implement that in the *run()* function: - -.. code-block:: python - - def run(self): - ... - # initial level set - initlevelset_input = self.get_input(2) - if initlevelset_input.is_data_available(): - # input set by previous operation in worflow - ... - else : - # input set by user - graphInput = self.get_input(1) - if graphInput.is_data_available(): - ... - else: - raise Exception("No initial level-set given: it must be graphics input or binary image.") - ... - -In the case of binary mask input, no extra code is needed and we just have to pass the input content to -the scikit-image functions as both structures are numpy arrays. - -.. code-block:: python - - def run(self): - ... - if initlevelset_input.is_data_available(): - initlevelSetBinary = initlevelset_input.get_image() - if param.method == "mgac": - proc_img = morphological_geodesic_active_contour(gimage, 100, init_level_set=initlevelSetBinary) - else: - proc_img = morphological_chan_vese(gimage, 100, init_level_set=initlevelSetBinary) - ... - -For graphics input, we need to generate a binary mask representing active contour seeds from graphics drawn by users. -We will use 2 methods of :py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask` to achieve that: - -- :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.create_graphics_mask`: create a binary mask from :py:class:`~ikomia.dataprocess.pydataprocess.CGraphicsInput` and append it to the internal mask list. -- :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.get_graphics_mask`: get a mask from the internal mask list as numpy array. - -.. code-block:: python - - def run(self): - ... - if graphInput.is_data_available(): - self.create_graphics_mask(imagef.shape[1], imagef.shape[0], graphInput) - binImg = self.get_graphics_mask(0) - ... - proc_img = morphological_geodesic_active_contour(gimage, 100, init_level_set=binImg, ...) - ... - proc_img = morphological_chan_vese(gimage, 100, init_level_set=binImg, ...) - ... - -The following example illustrates the use of user graphics input to define initial level set: - -.. image:: _static/interactive_plugin.jpg - -.. _results: - -Results -^^^^^^^ - -The first result is the binary mask representing the final level set of the active contour method. -We simply have to set the content of the corresponding output with the numpy array returned -by the scikit-image functions. - -.. code-block:: python - - # Get output - output = self.get_output(0) - # set output mask binary image - output.set_image(proc_img) - - -The second result is the visualization of the segmented objects on top of the original image. -We will use the color mask visualization offered by Ikomia software. This feature enables to -take an output mask (binary or grayscale image) and use it as color mask for another image output. -Ikomia software will then display the mask in a transparent overlay on top of this image. -Colors are fully customizable, you can set a single color for binary mask or a complete colormap for grayscale mask. - -In our example, we want to display the final level set on top of the original image, so we need -to forward the original input to a given output (see :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.forward_input_image`): - -.. code-block:: python - - self.forward_input_image(0, 1) - -And we apply the color mask vizualisation in red (see :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.set_output_color_map`): - -.. code-block:: python - - self.set_output_color_map(1, 0, [[255,0,0]]) - -.. _progress_bar: - -Progress bar -^^^^^^^^^^^^ - -Note that functions *morphological_geodesic_active_contour()* and *morphological_chan_vese()* from scikit-image -have one specificity that can be usefull for us. They have an *iter_callback* parameter called once per iteration -we can use to refresh the progress bar of Ikomia software. We call :py:meth:`~ikomia.core.pycore.CWorkflowTask.emit_step_progress` -in a lambda function given *to iter_callback* parameter: - -.. code-block:: python - - proc_img = morphological_geodesic_active_contour(..., iter_callback=(lambda callback: self.emit_step_progress()) - -We also need to specify the number of iterations (steps) to our progress bar by overriding -:py:meth:`~ikomia.core.pycore.CWorkflowTask.get_progress_steps`: - -.. code-block:: python - - class MorphoSnakes(dataprocess.C2dImageTask): - - def get_progress_steps(self, eltCount=1): - param = self.get_parameters() - if param.method == "mgac": - nb_iter = param.mgac_iterations - else : - nb_iter = param.mcv_iterations - - return nb_iter - -.. _process_parameters: - -Process parameters ------------------- - -We will now focus on adding some parameters to our process. We want to control available parameters from scikit-image methods. - -Morphological active contour: - -- gImage : (M, N) or (L, M, N) array, preprocessed image or volume to be segmented. -- iterations : uint, number of iterations to run. -- init_level_set : (M, N) array, or (L, M, N) array -- smoothing : uint, optional, number of time the smoothing operator is applied per iteration. -- threshold : float, optional, areas of the image with a value smaller than this threshold will be considered borders. -- balloon : float, optional, force to guide the contour, positive value → expand the contour / negative value → shrink the contour. -- iter_callback : function called once per iteration, optional - -Morphological Chan Vese: - -- gImage : (M, N) or (L, M, N) array, preprocessed image or volume to be segmented. -- iterations : uint, number of iterations to run. -- init_level_set : (M, N) array, or (L, M, N) array -- smoothing : uint, optional, number of time the smoothing operator is applied per iteration. -- lamnda1 : float, optional, weight parameter for the outer region. -- lamnda2 : float, optional,weight parameter for the inner region. -- iter_callback : function called once per iteration, optional - -First, we add member variables in the parameters class, they will be accessible from the process. -Note the presence of functions :py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.set_values` and -:py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.get_values()` which are required to save/load values when user wants to save his workflow. - -.. code-block:: python - - class MorphoSnakesParam(core.CWorkflowTaskParam): - - def __init__(self): - core.CWorkflowTaskParam.__init__(self) - # parameters - self.method = "mgac" - self.mgac_amplification_contour = "Inverse gaussian gradient" - self.mgac_iterations = 100 - self.mgac_smoothing = 1 - self.mgac_threshold = 'auto' - self.mgac_balloon = 0 - self.mcv_iterations = 100 - self.mcv_smoothing = 1 - self.mcv_lambda1 = 1 - self.mcv_lambda2 = 1 - - def set_values(self, params): - # Set parameters values from Ikomia application - self.method = int(params["method"]) - self.mgac_amplification_contour = int(params["mgac_amplification_contour"]) - self.mgac_iterations = int(params["mgac_iterations"]) - self.mgac_smoothing = int(params["mgac_smoothing"]) - self.mgac_threshold = int(params["mgac_threshold"]) - self.mgac_balloon = int(params["mgac_balloon"]) - self.mcv_iterations = int(params["mcv_iterations"]) - self.mcv_smoothing = int(params["mcv_smoothing"]) - self.mcv_lambda1 = int(params["mcv_lambda1"]) - self.mcv_lambda2 = int(params["mcv_lambda2"]) - - def get_values(self): - # Send parameters values to Ikomia application - # Create the specific dict structure (string container) - params = {} - params["method"] = str(self.method) - params["mgac_amplification_contour"] = str(self.mgac_amplification_contour) - params["mgac_iterations"] = str(self.mgac_iterations) - params["mgac_smoothing"] = str(self.mgac_smoothing) - params["mgac_threshold"] = str(self.mgac_threshold) - params["mgac_balloon"] = str(self.mgac_balloon) - params["mcv_iterations"] = str(self.mcv_iterations) - params["mcv_smoothing"] = str(self.mcv_smoothing) - params["mcv_lambda1"] = str(self.mcv_lambda1) - params["mcv_lambda2"] = str(self.mcv_lambda2) - return params - -We now modify the *run()* method to give parameters to our function: - -.. code-block:: python - - class MorphoSnakes(dataprocess.C2dImageTask): - - def run(self): - ... - # Get parameters - param = self.get_param_object() - ... - - proc_img = morphological_geodesic_active_contour( - gimage, - param.mgac_iterations, - init_level_set=initlevelSetBinary, - smoothing=param.mgac_smoothing, - threshold=param.mgac_threshold, - balloon=param.mgac_balloon, - iter_callback=(lambda callback: self.emit_step_progress())).astype(np.uint8) * 255 - -.. _process_widget: - -Process widget --------------- - -At this point, parameters are only available from source code. The role of the plugin widget is to open parameters -configuration to the user. We will use PyQt framework for this example. We implement the widget part in the file -*skimage_morpho_snakes_widget.py*. The widget layout is created in the constructor. Like the process class, -the constructor receives an instance of the parameters structure to initialize the widget components. - -We let the user choose the active contour method, so we need him to select the method in order to display -the appropriate parameters. We will use the **QStackedWidget** component. - -.. image:: _static/qstacked_widget.jpg - -Global widget initialization - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - - def __init__(self, param, parent): - # Create layout : QGridLayout by default - self.gridLayout = QGridLayout() - - # snake methods available - self.mgac = QWidget() - self.chanVese = QWidget() - - # set all parameters widgets - self.methodWidget() - self.mgacWidget() - self.chanVeseWidget() - - # main widget - self.stack = QStackedWidget() - self.stack.addWidget(self.mgac) - self.stack.addWidget(self.chanVese) - self.gridLayout.addWidget(self.stack, 2, 0) - self.gridLayout.setRowStretch(3,3) - - # PyQt -> Qt wrapping - layoutPtr = qtconversion.PyQtToQt(self.gridLayout) - - # Set widget layout - self.set_layout(layoutPtr) - - # update left parameter panel - if self.parameters.method != "mgac": - self.comboMethod.setCurrentIndex(1) - -Note: *self.gridLayout.setRowStretch(n, n)* forces items to stay on top of the gridlayout. - -Method selection: - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - ... - def methodWidget(self): - label_method = QLabel("Methods :") - self.comboMethod = QComboBox() - self.comboMethod.addItem("Morphological Geodesic Active Contour") - self.comboMethod.addItem("Morphological Chan Vese") - self.comboMethod.currentIndexChanged.connect(self.OnMethodChange) - - self.gridLayout.setRowStretch(0,0) - self.gridLayout.addWidget(label_method, 0, 0) - self.gridLayout.setRowStretch(1,1) - self.gridLayout.addWidget(self.comboMethod, 1, 0) - self.gridLayout.setRowStretch(2,2) - - -MGAC method parameters (see `source code `_ for details) - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - - def mgacWidget(self): - ... - - -Chan Vese method parameters (see `source code `_ for details) - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - - def chanVeseWidget(self): - ... - -We use the slot *self.OnMethodChange()* to change current index of our QStackWidget according to the selected method. - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - #pySlot - def OnMethodChange(self): - if self.comboMethod.currentText() == "Morphological Geodesic Active Contour": - self.stack.setCurrentIndex(0) - else : - self.stack.setCurrentIndex(1) - -Let’s see how our widget looks: - -.. image:: _static/parameters_CV.jpg - :width: 50% -.. image:: _static/parameters_MGAC.jpg - :width: 47% - -Last thing, we have to update process parameters when a user change values through the widget. -We do that by overriding *onApply()* method which is called when user clicks the *Apply* button. - -.. code-block:: python - - class MorphoSnakesWidget(core.CWorkflowTaskWidget): - - def onApply(self): - # Apply button clicked slot - if self.comboMethod.currentText() == "Morphological Geodesic Active Contour": - self.parameters.method = "mgac" - - if self.mgac_coutour_check.isChecked(): - self.parameters.mgac_amplification_contour = self.mgac_stack_comboContour.currentText() - else : - self.parameters.mgac_amplification_contour = None - - self.parameters.mgac_iterations = self.mgac_spin_iterations.value() - self.parameters.mgac_smoothing = self.mgac_spin_smooth.value() - - if self.mgac_threshold_check.isChecked(): - self.parameters.mgac_threshold = 'auto' - else : - self.parameters.mgac_threshold = self.mgac_spin_threshold.value() - - self.parameters.mgac_balloon = self.mgac_spin_balloon.value() - else : - self.parameters.method = "mcv" - self.parameters.mcv_iterations = self.mcv_spin_iterations.value() - self.parameters.mcv_smoothing = self.mcv_spin_smooth.value() - self.parameters.mcv_lambda1 = self.mcv_spin_lambda1.value() - self.parameters.mcv_lambda2 = self.mcv_spin_lambda2.value() - - # Send signal to launch the process - self.emitApply(self.parameters) - -.. _process_metadata: - -Process metadata ----------------- - -Finally, we will add some useful information about our plugin. Ikomia software manages such information and -display it to the user (parameters widget, Ikomia Apps). Metadata can be added in the constructor of the process -factory class in *skimage_morpho_snakes_process.py*. We have to fill the member object info, -see :py:class:`~ikomia.dataprocess.pydataprocess.CTaskInfo` for details. - -**Our plugin is now fully functional and interactive !** - -.. _source_code: - -Source code ------------ - -`requirements.txt `_ - -`skimage_morpho_snakes.py `_ - -`skimage_morpho_snakes_process.py `_ - -`skimage_morpho_snakes_widget.py `_ diff --git a/doc/source/modules.rst b/doc/source/modules.md similarity index 95% rename from doc/source/modules.rst rename to doc/source/modules.md index 92fbb199..26393ff0 100644 --- a/doc/source/modules.rst +++ b/doc/source/modules.md @@ -1,14 +1,13 @@ -API Reference -============= +# API Reference Ikomia API is divided into 4 main modules, each one may contain sub-modules. A large part of this API is based on C++ bindings, those classes are easily identifiable since we apply a naming convention where all C++ classes begin with the C capital letter. +```{eval-rst} .. rubric:: Utils module .. autosummary:: :toctree: _autosummary - :recursive: ikomia.utils.pyutils ikomia.utils.pyqtutils @@ -43,3 +42,4 @@ the C capital letter. ikomia.dnn.dataset ikomia.dnn.torch.models ikomia.dnn.torch.datasetmapper +``` \ No newline at end of file diff --git a/doc/source/naming.rst b/doc/source/naming.rst deleted file mode 100644 index e58824d1..00000000 --- a/doc/source/naming.rst +++ /dev/null @@ -1,12 +0,0 @@ -Naming convention -================= - -Ikomia plugins must follow a quiet strict naming convention to be loaded correctly. - -The Ikomia plugin loader use this convention to detect automatically required entry points. The rules are also introduced for reasons of homogeneity and clarity in Ikomia HUB. - - - main entry point in a file named my_plugin.py - - process implementation in a file named my_plugin_process.py - - widget implementation in a file named my_plugin_widget.py - - lowercase only - - use of character '_' as separator \ No newline at end of file diff --git a/doc/source/object_detection/index.md b/doc/source/object_detection/index.md new file mode 100644 index 00000000..3f22196c --- /dev/null +++ b/doc/source/object_detection/index.md @@ -0,0 +1,153 @@ +# First Steps in Object Detection with Ikomia API + +Ikomia API is a powerful tool for creating and managing computer vision workflows. + +In this tutorial, we will guide you through the process of creating an Object Detection solution using the Ikomia API. +Object Detection is a computer vision technique to identify and locate objects within an image or a video stream. +It combines image classification and localization tasks to recognize and locate multiple objects of interest in a single image. + +## The Problem + +In this tutorial, our goal is to detect and count airplanes from aerial images such as the one shown below: + +![](../_static/aerial_airplanes.jpg) + +```{important} +1. Please download this annotated dataset from roboflow : [https://universe.roboflow.com/ds/W8grf6DmCF?key=QkQVA4pg66](https://universe.roboflow.com/ds/W8grf6DmCF?key=QkQVA4pg66). +2. Create a specific folder **aerial** and extract the download zip files in it. +3. In **aerial**, you should see 3 folders (test, train, val) and text files. +``` +```python +# Set path to your annotated dataset +dataset_path = "/path/to/aerial" +``` +## Test Object Detection Algorithms + +There are many detection algorithms, you can find some of the best ones in the Ikomia HUB. + +In this section, we create and run your first Object Detection workflow. + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Initialize the workflow +wf = Workflow() + +# Add an Object Detection algorithm +yolo = wf.add_task(ik.infer_yolo_v7(), auto_connect=True) + +# Run on your image +wf.run_on(path=dataset_path+"/test/airport_246_jpg.rf.3d892810357f48026932d5412fa81574.jpg") + +# Inspect your results +display(yolo.get_image_with_graphics()) +``` +![](../_static/aerial_airplanes_box.png) + +The workflow consists of loading an image, applying an Object Detection algorithm, and visualizing the results. If you are not familiar with the Ikomia API, please refer to the [Getting Started](../getting_started) page. + +At this stage, we can observe that the results are not satisfactory. The main reason is that `infer_yolo_v7` uses a default model trained on the COCO dataset. +This dataset contains thousands of images, but no aerial images of airports, so the model doesn't know what an airplane looks like from above. + +That's why you downloaded the previous dataset. You now have hundreds of images annotated by humans (bounding box around airplanes in aerial images), and we are going to exploit them. + +## Train Your Custom Model + +With the dataset of aerial images that you downloaded, you can train a custom YOLO v7 model using Ikomia API. +The downloaded dataset is in YOLO format, which means that for each image in each folder (test, val, train), there is a corresponding .txt file containing all bounding box and class information associated with airplanes. +Additionally, there is a `_darknet.labels` file containing all class names. + +To load the custom data and annotations, we will use the dataset_yolo module provided by Ikomia API. Here's how you can train your custom model: + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik + +# Initialize the workflow +wf = Workflow() + +# Add a dataset loader to load your custom data and annotations +dataset = wf.add_task(ik.dataset_yolo( + dataset_folder=dataset_path+"/train", + class_file_path=dataset_path+"/train/_darknet.labels" + ) +) + +# Add a training algorithm +yolo = wf.add_task(ik.train_yolo_v7( + batch_size="4", + epochs="10", + output_folder="output_folder" + ), + auto_connect=True +) + +# Launch your training on your data +wf.run() +``` +In the above code, we first create a new Workflow object and add a `dataset_yolo` task to load our custom data and annotations. +We pass the path to the folder containing the training data (folder_path) and the path to the `_darknet.labels` file containing the class names (class_file_path) as arguments to the task. + +Next, we add a `train_yolo_v7` task to train our custom YOLO v7 model. We specify the batch size (`batch_size`) and the number of epochs (`epochs`) to train for. +We also specify the output folder path (`output_folder`) where the trained model will be saved. The `auto_connect=True` argument ensures that the output of the `dataset_yolo` task is automatically connected to the input of the `train_yolo_v7` task. + +Finally, we run the workflow to start the training process. You can monitor the progress of your training using tools like Tensorboard or MLFlow. + +Once the training is complete, the `train_yolo_v7` task will save the best model in a timestamped folder inside the `output_folder`. You can find your `best.pt` model in the weights subfolder. + +To test and evaluate your own model on your images, you can use the following code: +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils.displayIO import display +from ikomia.utils import ik + +# Initialize the workflow +wf = Workflow() + +# Add an Object Detection algorithm +yolo = wf.add_task(ik.infer_yolo_v7( + model_name_or_path="output_folder/[timestamp]/weights/best.pt", + conf_thres="0.4" + ), + auto_connect=True) + +# Run on your image +wf.run_on(path=dataset_path+"/test/airport_246_jpg.rf.3d892810357f48026932d5412fa81574.jpg") + +# Inspect your results +display(yolo.get_image_with_graphics()) +``` +![](../_static/aerial_airplanes_trained.png) + +Here, we add an `infer_yolo_v7` task to apply our trained model for object detection on the image. We specify the path to our trained model using the `custom_model` argument. +We then run the workflow on the same image that we used previously. + +Once you have performed the object detection, you may need to use the results in your application. Here is an example of how you can extract the results using YOLO: + +```python +# Get results +results = yolo.get_results() +# Get results as list of objects +objects = results.get_objects() +# Convert results to JSON +results_json = results.to_json() +``` +The `get_results()` method returns a `CObjectDetectionIO` object containing the detected objects and their respective bounding boxes. +You can then use the `to_json()` method to convert the `CObjectDetectionIO` object to a JSON string, which can be further processed by your application. + +Finally, you can get the total number of airplanes for each image: +```python +print(f"Total number of airplanes : {len(objects)}") +``` + +## Conclusion + +In this tutorial, we have shown how to use YOLOv7 to perform object detection on images and videos. +We have covered the steps required to train a custom YOLOv7 model, as well as how to use a pre-trained model to detect objects in real-time. +We have also explored how to fine-tune the model to improve its accuracy on specific object classes. + +YOLOv7 is a powerful object detection algorithm that can be used in a wide range of applications, from surveillance systems to self-driving cars. +By following the steps outlined in this tutorial, you should have a good understanding of how YOLOv7 works and how to use it to detect objects in your own images and videos. +With some practice and experimentation, you can fine-tune the algorithm to suit your specific needs and achieve even better results. \ No newline at end of file diff --git a/doc/source/opencv_plugin.rst b/doc/source/opencv_plugin.rst deleted file mode 100644 index cbd0996f..00000000 --- a/doc/source/opencv_plugin.rst +++ /dev/null @@ -1,303 +0,0 @@ -Simple OpenCV plugin -==================== - -This section will show how to create a fully functional plugin applying basics OpenCV methods to images. It takes image as input and delivers processed image as output. - -We skip here all steps to create a new empty plugin. Please refer to :doc:`Hello World tutorial ` if you are not familiar with it. - -At this point, a plugin called *ocv_basics* is created with the following structure: - .../*BasicsOpenCV/* - - *__init__.py* - - *ocv_basics.py* - - *ocv_basics_process.py* - - *ocv_basics_widget.py* - -Interface implementation ------------------------- - -No features added from the default implementation. -See :doc:`ocv_basics.py `. - - -Process implementation ----------------------- - -The aim of our plugin is to process images, so our task is derived from :py:class:`~~ikomia.dataprocess.pydataprocess.C2dImageTask`. -This base class comes with default inputs (image + graphics) and outputs (image) that fit our needs. - -Our process pipeline will be: *Convert to grayscale* -> *Gaussian blur* -> *Canny filter*. - -The first thing to do in our *ocv_basics_process.py* is importing OpenCV package (already installed with Ikomia Studio): - -.. code-block:: python - - from ikomia import core, dataprocess - import copy - # Your imports below - import cv2 - -In the *run* method, we now have to retrieve source image from input, add OpenCV calls and set the output: - -.. code-block:: python - - class OCVBasics(dataprocess.C2dImageTask): - - #... - - def run(self): - # Core function of your process - # Call begin_task_run for initialization - self.begin_task_run() - - # Get input : - input_img = self.get_input(0) - - # Get image from input (numpy array): - src_image = input_img.get_image() - - # Call to the process main routine - # Grayscale conversion - proc_img = cv2.cvtColor(src_image, cv2.COLOR_RGB2GRAY) - # Gaussian blur - proc_img = cv2.GaussianBlur(proc_img, (5,5), 1) - # Canny filter - proc_img = cv2.Canny(proc_img, 0, 255) - - # Get output : - output = self.get_output(0) - - # Set image of output (numpy array): - output.set_image(proc_img) - - # Step progress bar: - self.emit_step_progress() - - # Call end_task_run to finalize process - self.end_task_run() - -Reload plugin in Ikomia software (with Plugin Manager or in the main menu), add it to a new workflow to test the results. You should have this: - -.. image:: _static/opencv_plugin.jpg - - -Process parameters ------------------- - -We will focus now on adding some parameters to our process ((in *ocv_basics_process.py*). -Let's say we want to control blur strength of the Gaussian filter, we have to manage at least 3 parameters: - -- Kernel size -- Sigma X -- Sigma Y - -First, we add member variables in the parameters class, they will be accessible from the process. -Note the presence of functions :py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.set_parametersMap` and :py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.get_parametersMap` -which are required to save/load values when user wants to save his workflow. - -.. code-block:: python - - class OCVBasicsParam(core.CWorkflowTaskParam): - - def __init__(self): - core.CWorkflowTaskParam.__init__(self) - # Place default value initialization here - self.kernel_size = (3, 3) - self.sigma_x = 1.0 - self.sigma_y = 1.0 - - def set_values(self, params): - # Set parameters values from Ikomia application (user inputs) - # Parameters values are stored as string and accessible like a python dict - self.kernel_size = (int(params["kernel_size_x"]), int(params["kernel_size_y"])) - self.sigma_x = int(params["sigma_x"]) - self.sigma_y = int(params["sigma_y"]) - - def get_values(self): - # Send parameters values to Ikomia application (workflow) - # Create the specific dict structure (string container) - params = {} - params["kernel_size_x"] = str(self.kernel_size[0]) - params["kernel_size_y"] = str(self.kernel_size[1]) - params["sigma_x"] = str(self.sigma_x) - params["sigma_y"] = str(self.sigma_y) - return params - -We are now able to manage parameters from the process. The constructor receives an instance of the parameters structure that we should copy. This instance has values set from the Ikomia application (default or user-defined). - -.. code-block:: python - - class OCVBasics(dataprocess.C2dImageTask): - - def __init__(self, name, param): - dataprocess.C2dImageTask.__init__(self, name) - - #Create parameters class - if param is None: - self.set_param_object(OCVBasicsParam()) - else: - self.set_param_object(copy.deepcopy(param)) - -Finally, we modify the *run* method to pass parameters to GaussianBlur function: - -.. code-block:: python - - class OCVBasics(dataprocess.C2dImageTask): - - def run(self): - # Core function of your process - # Call begin_task_run for initialization - self.begin_task_run() - - # Get parameters : - param = self.get_param_object() - - #... - - # Gaussian blur - proc_img = cv2.GaussianBlur(proc_img, param.kernel_size, param.sigma_x, param.sigma_y) - - #... - -Process widget --------------- - -At this point, parameters are only available from source code. -The role of the plugin widget is to open parameters configuration to the user. -We will use PyQt framework for this example. - -.. note:: You can also use PySide2 (another Qt-based framework supported by Qt) for your widget. - -We implement the widget part in the file *OCVBasics_widget.py*. -The widget layout is created in the constructor. -Like the process class, the constructor receives an instance of the parameters structure to initialize the widget components. - -.. code-block:: python - - class OCVBasicsWidget(core.CWorkflowTaskWidget): - - def __init__(self, param, parent): - core.CWorkflowTaskWidget.__init__(self, parent) - - if param is None: - self.parameters = OCVBasicsParam() - else: - self.parameters = param - - # Create layout : QGridLayout by default - self.gridLayout = QGridLayout() - - # Kernel size - label_kernel_size = QLabel('Kernel size:') - - self.spin_kernel_x = QSpinBox() - self.spin_kernel_x.setRange(1, 99) - self.spin_kernel_x.setSingleStep(2) - self.spin_kernel_x.setValue(self.parameters.kernel_size[0]) - - self.spin_kernel_y = QSpinBox() - self.spin_kernel_y.setRange(1, 99) - self.spin_kernel_y.setSingleStep(2) - self.spin_kernel_y.setValue(self.parameters.kernel_size[1]) - - self.gridLayout.addWidget(label_kernel_size, 0, 0) - self.gridLayout.addWidget(self.spin_kernel_x, 0, 1) - self.gridLayout.addWidget(self.spin_kernel_y, 0, 2) - - # Sigma X - label_sigma_x = QLabel('Sigma X:') - self.spin_sigma_x = QDoubleSpinBox() - self.spin_sigma_x.setRange(0.0, 255.0) - self.spin_sigma_x.setSingleStep(0.1) - self.spin_sigma_x.setValue(self.parameters.sigma_x) - - self.gridLayout.addWidget(label_sigma_x, 1, 0) - self.gridLayout.addWidget(self.spin_sigma_x, 1, 1) - - # Sigma Y - label_sigma_y = QLabel('Sigma Y:') - self.spin_sigma_y = QDoubleSpinBox() - self.spin_sigma_y.setRange(0.0, 255.0) - self.spin_sigma_y.setSingleStep(0.1) - self.spin_sigma_y.setValue(self.parameters.sigma_y) - - self.gridLayout.addWidget(label_sigma_y, 2, 0) - self.gridLayout.addWidget(self.spin_sigma_y, 2, 1) - - # PyQt -> Qt wrapping (C++ handle) - layoutPtr = qtconversion.PyQtToQt(self.gridLayout) - - # Set widget layout - self.set_layout(layoutPtr) - -In Ikomia, plugin widgets are shown in 2 different places: - -- in a popup windows when you add a plugin to the workflow (from the process library pane) -- in the Workflow Creator window where you can see parameters of the current task - -Let's see how our widget looks: - -.. image:: _static/opencv_plugin_widget.jpg - -Last thing, we have to update process parameters when a user change values through the widget. -We do that by overriding :py:meth:`~~ikomia.core.pycore.CWorkflowTaskWidget.onApply` method. -It is called when user clicks the *Apply* button. - -.. code-block:: python - - class OCVBasicsWidget(core.CWorkflowTaskWidget): - # ... - - def onApply(self): - # Apply button has been pressed - # Get parameters value from widget components - self.parameters.kernel_size = (self.spin_kernel_x.value(), self.spin_kernel_y.value()) - self.parameters.sigma_x = self.spin_sigma_x.value() - self.parameters.sigma_y = self.spin_sigma_y.value() - - # Send signal to launch the process - self.emit_apply(self.parameters) - -Our plugin is now fully functional! - -Process metadata ----------------- - -Finally, we will add some useful information about our plugin. -Ikomia software manages such information and display it to the user (parameters widget, Ikomia Store). -Metadata can be added in the constructor of the process factory class in *OCVBasics_process.py*. -We have to fill the member object *info*, see :py:class:`~~ikomia.dataprocess.pydataprocess.CTaskInfo` for details. - -.. code-block:: python - - class OCVBasicsFactory(dataprocess.CTaskFactory): - - def __init__(self): - dataprocess.CTaskFactory.__init__(self) - # Set process information as string here - self.info.name = "OCVBasics" - self.info.shortDescription = "OpenCV Canny" - self.info.description = "Simple OpenCV pipeline that computes Canny filter" - self.info.authors = "Ikomia team" - self.info.article = "" - self.info.journal = "" - self.info.year = 2020 - self.info.license = "MIT License" - self.info.version = "1.0.0" - self.info.repo = "https://github.com/Ikomia-dev" - self.info.documentationLink = "https://ikomia.com" - # relative path -> as displayed in Ikomia application process tree - self.info.path = "Plugins/Python/Ikomia/Examples" - # If you want to customize plugin icon - self.info.iconPath = "" - # Associated keywords, for search - self.info.keywords = "OpenCV,blur,grayscale,canny,edge,gaussian" - - -Source code ------------ - -:doc:`ocv_basics.py ` - -:doc:`ocv_basics_process.py ` - -:doc:`ocv_basics_widget.py ` \ No newline at end of file diff --git a/doc/source/opencv_plugin_interface.rst b/doc/source/opencv_plugin_interface.rst deleted file mode 100644 index b2e25124..00000000 --- a/doc/source/opencv_plugin_interface.rst +++ /dev/null @@ -1,28 +0,0 @@ -Plugin interface -================== - -Code example for ocv_basics plugin interface. - -.. code-block:: python - - from ikomia import dataprocess - - - # -------------------- - # - Interface class to integrate the process with Ikomia application - # - Inherits dataprocess.CPluginProcessInterface from Ikomia API - # -------------------- - class IkomiaPlugin(dataprocess.CPluginProcessInterface): - - def __init__(self): - dataprocess.CPluginProcessInterface.__init__(self) - - def getProcessFactory(self): - # Instantiate process object - from ocv_basics.ocv_basics_process import OCVBasicsFactory - return OCVBasicsFactory() - - def getWidgetFactory(self): - # Instantiate associated widget object - from ocv_basics.ocv_basics_widget import OCVBasicsWidgetFactory - return OCVBasicsWidgetFactory() \ No newline at end of file diff --git a/doc/source/opencv_plugin_process.rst b/doc/source/opencv_plugin_process.rst deleted file mode 100644 index e2de2382..00000000 --- a/doc/source/opencv_plugin_process.rst +++ /dev/null @@ -1,131 +0,0 @@ -Process -======= - -Code example for OCVBasics process implementation - -.. code-block:: python - - from ikomia import core, dataprocess - import copy - # Your imports below - import cv2 - - # -------------------- - # - Class to handle the process parameters - # - Inherits core.CProtocolTaskParam from Ikomia API - # -------------------- - class OCVBasicsParam(core.CWorkflowTaskParam): - - def __init__(self): - core.CWorkflowTaskParam.__init__(self) - # Place default value initialization here - self.kernel_size = (3, 3) - self.sigma_x = 1.0 - self.sigma_y = 1.0 - - def set_values(self, params): - # Set parameters values from Ikomia application (user inputs) - # Parameters values are stored as string and accessible like a python dict - self.kernel_size = (int(params["kernel_size_x"]), int(params["kernel_size_y"])) - self.sigma_x = int(params["sigma_x"]) - self.sigma_y = int(params["sigma_y"]) - - def get_values(self): - # Send parameters values to Ikomia application (workflow) - # Create the specific dict structure (string container) - params = {} - params["kernel_size_x"] = str(self.kernel_size[0]) - params["kernel_size_y"] = str(self.kernel_size[1]) - params["sigma_x"] = str(self.sigma_x) - params["sigma_y"] = str(self.sigma_y) - return params - - - # -------------------- - # - Class which implements the process - # - Inherits core.CProtocolTask or derived from Ikomia API - # -------------------- - class OCVBasics(dataprocess.C2dImageTask): - - def __init__(self, name, param): - dataprocess.C2dImageTask.__init__(self, name) - # Add input/output of the process here - # Example : self.add_input(core.CImageProcessIO()) - # self.add_output(core.CImageProcessIO()) - - #Create parameters class - if param is None: - self.set_param_object(OCVBasicsParam()) - else: - self.set_param_object(copy.deepcopy(param)) - - def get_progress_steps(self): - # Function returning the number of progress steps for this process - # This is handled by the main progress bar of Ikomia application - return 1 - - def run(self): - # Core function of your process - # Call begin_task_run for initialization - self.begin_task_run() - - # Get parameters : - param = self.get_param_object() - - # Get input : - input_img = self.get_input(0) - - # Get image from input (numpy array): - src_image = input_img.get_image() - - # Call to the process main routine - # Grayscale conversion - proc_img = cv2.cvtColor(src_image, cv2.COLOR_RGB2GRAY) - # Gaussian blur - proc_img = cv2.GaussianBlur(proc_img, param.kernel_size, param.sigma_x, param.sigma_y) - # Canny filter - proc_img = cv2.Canny(proc_img, 0, 255) - - # Get output : - output = self.get_output(0) - - # Set image of output (numpy array): - output.set_image(proc_img) - - # Step progress bar: - self.emit_step_progress() - - # Call end_task_run to finalize process - self.end_task_run() - - - # -------------------- - # - Factory class to build process object - # - Inherits dataprocess.CTaskFactory from Ikomia API - # -------------------- - class OCVBasicsFactory(dataprocess.CTaskFactory): - - def __init__(self): - dataprocess.CTaskFactory.__init__(self) - # Set process information as string here - self.info.name = "ocv_basics" - self.info.shortDescription = "OpenCV Canny" - self.info.description = "Simple OpenCV pipeline that computes Canny filter" - self.info.authors = "Ikomia team" - self.info.article = "" - self.info.journal = "" - self.info.year = 2020 - self.info.license = "MIT License" - self.info.version = "1.0.0" - self.info.repo = "https://github.com/Ikomia-dev" - self.info.documentationLink = "https://ikomia.com" - # relative path -> as displayed in Ikomia application process tree - self.info.path = "Plugins/Python/Ikomia/Examples" - # If you want to customize plugin icon - self.info.iconPath = "" - # Associated keywords, for search - self.info.keywords = "OpenCV,blur,grayscale,canny,edge,gaussian" - - def create(self, param=None): - # Create process object - return OCVBasics(self.info.name, param) diff --git a/doc/source/opencv_plugin_widget.rst b/doc/source/opencv_plugin_widget.rst deleted file mode 100644 index 8d406a1f..00000000 --- a/doc/source/opencv_plugin_widget.rst +++ /dev/null @@ -1,99 +0,0 @@ -Widget -====== - -Code example for OCVBasics widget implementation - -.. code-block:: python - - from ikomia import core, dataprocess - from ikomia.utils import qtconversion - from ocv_basics.ocv_basics_process import OCVBasicsParam - #PyQt GUI framework - from PyQt5.QtWidgets import * - - - # -------------------- - # - Class which implements widget associated with the process - # - Inherits core.CProtocolTaskWidget from Ikomia API - # -------------------- - class OCVBasicsWidget(core.CWorkflowTaskWidget): - - def __init__(self, param, parent): - core.CWorkflowTaskWidget.__init__(self, parent) - - if param is None: - self.parameters = OCVBasicsParam() - else: - self.parameters = param - - # Create layout : QGridLayout by default - self.gridLayout = QGridLayout() - - # Kernel size - label_kernel_size = QLabel('Kernel size:') - - self.spin_kernel_x = QSpinBox() - self.spin_kernel_x.setRange(1, 99) - self.spin_kernel_x.setSingleStep(2) - self.spin_kernel_x.setValue(self.parameters.kernel_size[0]) - - self.spin_kernel_y = QSpinBox() - self.spin_kernel_y.setRange(1, 99) - self.spin_kernel_y.setSingleStep(2) - self.spin_kernel_y.setValue(self.parameters.kernel_size[1]) - - self.gridLayout.addWidget(label_kernel_size, 0, 0) - self.gridLayout.addWidget(self.spin_kernel_x, 0, 1) - self.gridLayout.addWidget(self.spin_kernel_y, 0, 2) - - # Sigma X - label_sigma_x = QLabel('Sigma X:') - self.spin_sigma_x = QDoubleSpinBox() - self.spin_sigma_x.setRange(0.0, 255.0) - self.spin_sigma_x.setSingleStep(0.1) - self.spin_sigma_x.setValue(self.parameters.sigma_x) - - self.gridLayout.addWidget(label_sigma_x, 1, 0) - self.gridLayout.addWidget(self.spin_sigma_x, 1, 1) - - # Sigma Y - label_sigma_y = QLabel('Sigma Y:') - self.spin_sigma_y = QDoubleSpinBox() - self.spin_sigma_y.setRange(0.0, 255.0) - self.spin_sigma_y.setSingleStep(0.1) - self.spin_sigma_y.setValue(self.parameters.sigma_y) - - self.gridLayout.addWidget(label_sigma_y, 2, 0) - self.gridLayout.addWidget(self.spin_sigma_y, 2, 1) - - # PyQt -> Qt wrapping (C++ handle) - layoutPtr = qtconversion.PyQtToQt(self.gridLayout) - - # Set widget layout - self.setLayout(layoutPtr) - - def onApply(self): - # Apply button has been pressed - # Get parameters value from widget components - self.parameters.kernel_size = (self.spin_kernel_x.value(), self.spin_kernel_y.value()) - self.parameters.sigma_x = self.spin_sigma_x.value() - self.parameters.sigma_y = self.spin_sigma_y.value() - - # Send signal to launch the process - self.emitApply(self.parameters) - - - #-------------------- - #- Factory class to build process widget object - #- Inherits dataprocess.CWidgetFactory from Ikomia API - #-------------------- - class OCVBasicsWidgetFactory(dataprocess.CWidgetFactory): - - def __init__(self): - dataprocess.CWidgetFactory.__init__(self) - # Set the name of the process -> it must be the same as the one declared in the process factory class - self.name = "ocv_basics" - - def create(self, param): - # Create widget object - return OCVBasicsWidget(param, None) diff --git a/doc/source/plugin_io.rst b/doc/source/plugin_io.rst deleted file mode 100644 index 59e3d825..00000000 --- a/doc/source/plugin_io.rst +++ /dev/null @@ -1,508 +0,0 @@ -Input/Output management -======================= - - -Every algorithm in Ikomia platform comes with a list of inputs and outputs. Depending of the algorithm, -you will have to deal with several types. This API provides a comprehensive list of I/O types to -address common needs in Computer Vision. - -- :ref:`Image` -- :ref:`Graphics` -- :ref:`Numeric values` -- :ref:`String values` -- :ref:`Blob measures` -- :ref:`Multi-dimensional array` -- :ref:`Deep learning dataset` -- :ref:`Filesystem path` -- :ref:`Object detection` -- :ref:`Instance segmentation` -- :ref:`Semantic segmentation` - - -Ideally, inputs and outputs should be defined in the constructor of the task. - -.. note:: - In some case, you may need to dynamically set inputs and/or outputs based on parameters values. You can handle such case by implementing - :py:meth:`~ikomia.core.pycore.CWorkflowTask.parameters_modified` and calling either :py:meth:`~ikomia.core.pycore.CWorkflowTask.add_input` or - :py:meth:`~ikomia.core.pycore.CWorkflowTask.remove_input` from your task class. - - -Image ------ - -:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`: input or output containing image data stored as Numpy array with dimensions [HWC]. -When the number of channels is 3, the color format should be RGB. - -Basic usage: - -.. code-block:: python - - from ikomia import core, dataprocess - - class MyPlugin(core.CWorkflowTask): - def init(self, name, param): - # Add image input - self.add_input(dataprocess.CImageIO()) - # Add image output - self.add_output(dataprocess.CImageIO()) - - def run(self): - # Get input - image_input = self.get_input(0) - # Get image as Numpy array - image = image_input.get_image() - -Please consult :py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO` for details. - - -Graphics --------- - -In Ikomia platform, graphics represent all vectorial items (line, polygon, text...) that -bring additionnal information to images. They can be stored as input (:py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsInput`) -or output (:py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsOutput`). Different types of graphics -are provided, each one being implemented in a dedicated class: - -- Point: :py:mod:`~ikomia.core.pycore.CGraphicsPoint` -- Polyline: :py:mod:`~ikomia.core.pycore.CGraphicsPolyline` -- Rectangle/Square: :py:mod:`~ikomia.core.pycore.CGraphicsRectangle` -- Ellipse/Circle: :py:mod:`~ikomia.core.pycore.CGraphicsEllipse` -- Polygon: :py:mod:`~ikomia.core.pycore.CGraphicsPolygon` -- Polygon with hole(s): :py:mod:`~ikomia.core.pycore.CGraphicsComplexPolygon` -- Text: :py:mod:`~ikomia.core.pycore.CGraphicsText` - -Basic usage: - -.. code-block:: python - - from ikomia import core, dataprocess - - class MyPlugin(core.CWorkflowTask): - def init(self, name, param): - # Add graphics input - self.add_input(dataprocess.CGraphicsInput()) - # Add graphics output - self.add_output(dataprocess.CGraphicsOutput()) - - def run(self): - # Get graphics input: from another algorithm or user - graphics_input = self.get_input(0) - items = graphics_input.get_items() - - for item in items: - if item.getType() == core.GraphicsItem.RECTANGLE: - top_left = (item.x, item.y) - width = item.width - height = item.height - - # Fill graphics output - graphics_output = self.get_output(0) - graphics_output.add_ellipse(0, 0, 100, 200) - graphics_output.add_item(core.CGraphicRectangle(0, 0, 100, 200)) - -.. note:: - - In Ikomia Studio, you can display items of graphics output as an overlay layer on top of an image I/O. You just have to call :py:meth:`~ikomia.dataprocess.pydataprocess.CGraphicsOutput.set_image_index` and specify the index of the desired image I/O. - - Some useful functions are implemented in :py:mod:`~ikomia.dataprocess.pydataprocess.C2dImageTask` to manage graphics items. - - From :py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO` you can burn items of a :py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsOutput` object directly into the image array. See :py:meth:`~ikomia.dataprocess.pydataprocess.CImageIO.get_image_with_graphics` and :py:meth:`~ikomia.dataprocess.pydataprocess.CImageIO.draw_graphics`. - - -Numeric values --------------- - -:py:mod:`~ikomia.dataprocess.pydataprocess.CNumericIO`: input or output dedicated to handle numeric values as float. -Data structure is organized to be visualize in a column/row table. You can also add labels describing -those values: *header labels* for columns and *labels* for rows. - -Basic usage: - -.. code-block:: python - - from ikomia import core, dataprocess - - class MyPlugin(core.CWorkflowTask): - def init(self, name, param): - # Add numeric output - self.add_output(dataprocess.CNumericIO()) - - def run(self): - # Fill numeric output - header = "Confidence" - labels = ["Car", "Truck", "Moto", "Bike", "Plane", "Train"] - confidences = [0.8, 0.75, 0.2, 0.05, 0.04, 0.01] - numeric_output = self.get_output(0) - numeric_output.set_output_type(dataprocess.NumericOutputType.TABLE) - numeric_output.add_value_list(confidences, header, labels) - -.. note:: - In Ikomia Studio, :py:mod:`~ikomia.dataprocess.pydataprocess.CNumericIO` can be display differently depending on the value set with :py:meth:`~ikomia.dataprocess.pydataprocess.CNumericIO.set_output_type`. - Possible values are listed in :py:mod:`~ikomia.dataprocess.pydataprocess.NumericOutputType`. If **PLOT** is choosen, then you have to select the plot type with :py:meth:`~ikomia.dataprocess.pydataprocess.CNumericIO.set_plot_type`. - -Basic usage: - -.. code-block:: python - - from ikomia import core, dataprocess - - class MyPlugin(core.CWorkflowTask): - def init(self, name, param): - # Add numeric output - self.add_output(dataprocess.CNumericIO()) - - def run(self): - # Fill numeric output - header = "Confidence" - labels = ["Car", "Truck", "Moto", "Bike", "Plane", "Train"] - confidences = [0.8, 0.75, 0.2, 0.05, 0.04, 0.01] - numeric_output = self.get_output(0) - numeric_output.set_output_type(dataprocess.NumericOutputType.TABLE) - numeric_output.add_value_list(confidences, header, labels) - - -String values --------------- - -:py:mod:`~ikomia.dataprocess.pydataprocess.CDataStringIO`: input or output dedicated to output string values. -Data structure is organized to be visualize in a column/row table. You can also add labels describing -those values: header labels for columns and labels for rows. - -Basic usage: - -.. code-block:: python - - from ikomia import core, dataprocess - - class MyPlugin(core.CWorkflowTask): - def init(self, name, param): - # Add numeric output - self.add_output(dataprocess.CDataStringIO()) - - def run(self): - # Fill numeric output - header = "TextRecognition" - labels = ["Distributor", "Date", "Article", "Price", "Currency"] - ocr_res = ["eShop", "04/12/2021", "smartphone", "199.90", "euro"] - numeric_output = self.get_output(0) - numeric_output.set_output_type(dataprocess.NumericOutputType.TABLE) - numeric_output.add_value_list(ocr_res, header, labels) - - -Blob measures -------------- - -:py:mod:`~ikomia.dataprocess.pydataprocess.CBlobMeasureIO`: input or output dedicated to handle measures computed on BLOBs (Binary Large Objects). -BLOBs are regions or connected components extracted from image based on specific properties (color, brightness, edges...). A CBlobMeasureIO instance -stores a list of :py:mod:`~ikomia.dataprocess.pydataprocess.CObjectMeasure` (one for each BLOB). Here is the list of available measures: - -- Surface (core.MeasureId.SURFACE) -- Perimeter (core.MeasureId.PERIMETER) -- Centroïd (core.MeasureId.CENTROID) -- Bounding box (core.MeasureId.BBOX): top-left point coordinates, width, height -- Oriented bounding box (core.MeasureId.ORIENTED_BBOX): center point coordinates, width, height, angle of rotation -- Equivalent diameter (core.MeasureId.EQUIVALENT_DIAMETER): diameter of the minimum enclosing circle computed from the surface -- Elongation (core.MeasureId.ELONGATION): elongation factor computed from moments (R. Mukundan and K.R. Ramakrishnan. Moment Functions in Image Analysis –Theory and Applications. World Scientific, 1998) -- Circularity (core.MeasureId.CIRCULARITY): circularity factor in [0, 1] computed from surface and perimeter -- Solidity (core.MeasureId.SOLIDITY): compactness factor defined as a ratio between blob surface and convex hull surface - -BLOB measure can be associated with a graphics element from a :py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsOutput` and store the corresponding -graphics id in :py:mod:`~ikomia.dataprocess.pydataprocess.CObjectMeasure`. - -Basic usage: - -.. code-block:: python - - from ikomia.core import CWorkflowTask, CMeasure, MeasureId - from ikomia.dataprocess import CBlobMeasureIO, CObjectMeasure - - class MyPlugin(CWorkflowTask): - def init(self, name, param): - # Add BLOB measure output - self.add_output(CBlobMeasureIO()) - - def run(self): - # Fill blob measure output - blob_output = self.get_output(0) - boxes, confidences = my_object_detection_func() - measures = [] - graphics_id = -1 - - for box, conf in zip(boxes, confidences): - measures.append(CObjectMeasure(CMeasure(MeasureId.BBOX), [box.x, box.y, box.width, box.height], graphics_id, "label")) - measures.append(CObjectMeasure(CMeasure(MeasureId.CUSTOM, "Confidence"), conf, graphics_id, "label")) - blob_output.add_object_measures(measures) - - -.. note:: In Ikomia Studio, :py:mod:`~ikomia.dataprocess.pydataprocess.CBlobMeasureIO` outputs are visualized in tables. - - -Multi-dimensional array ------------------------ - -:py:mod:`~ikomia.dataprocess.pydataprocess.CArrayIO`: input or output dedicated to handle multi-dimensional array. -:py:mod:`~ikomia.dataprocess.pydataprocess.CArrayIO` instance just stores a Numpy array that will be not considered as image. -Thus, such I/O are not visualized in Ikomia Studio. - - -Deep learning dataset ---------------------- - -:py:mod:`~ikomia.dnn.datasetio.IkDatasetIO`: input or output dedicated to handle deep learning image dataset. The Ikomia platform aims -to simplify the use of state of the art algorithms, especially training algorithms. The idea behind :py:mod:`~ikomia.dnn.datasetio.IkDatasetIO` -is to define a common structure so that every datasets converted to Ikomia format can then be used by any training algorithms from Ikomia -HUB. Ikomia dataset structure is inspired by PyTorch and Detectron2. It is composed of a global dict with 2 main entries -‘images’ and ‘metadata’. - -This API provides built-in function to manage standard dataset format: - -- COCO (2017): :py:func:`~ikomia.dnn.dataset.load_coco_dataset`. -- PASCAL-VOC (2012): :py:func:`~ikomia.dnn.dataset.load_pascalvoc_dataset`. -- VIA (VGG Image Annotator): :py:func:`~ikomia.dnn.dataset.load_via_dataset`. -- YOLO: :py:func:`~ikomia.dnn.dataset.load_yolo_dataset`. - -More information in :py:mod:`~ikomia.dnn.dataset`. - -Basic usage: - -.. code-block:: python - - from ikomia.core import CWorkflowTask - from ikomia.dnn.datasetio import IkDatasetIO - - class MyPlugin(CWorkflowTask): - def init(self, name, param): - # Add dataset input - self.add_input(IkDatasetIO()) - # Add dataset output - self.add_output(IkDatasetIO()) - - def run(self): - # Load dataset - dataset = self.get_output(0) - dataset.data = my_dataset_loader_func() - -.. note:: - You will find other dataset loaders in Ikomia HUB. You can also consult our GitHub repository to find implementation details (dataset_wgisd for example). - - -Filesystem path ---------------- - -:py:mod:`~ikomia.dataprocess.pydataprocess.CPathIO`: input or output dedicated to handle folder or file path. - -Basic usage: - -.. code-block:: python - - import os - from ikomia.core import CWorkflowTask, IODataType - from ikomia.dataprocess import CPathIO - - class MyPlugin(CWorkflowTask): - def init(self, name, param): - # Add path input - self.add_input(CPathIO(IODataType.FILE_PATH)) - # Add path output - default_path = "/usr/local" - self.add_output(CPathIO(IODataType.FOLDER_PATH, default_path)) - - def run(self): - # Get path - path_input = self.get_input(0) - path_in = path_input.get_path() - - # Set path - path_output = self.get_output(0) - path_output.set_path(os.path.dirname(path_in)) - - -Object detection I/O --------------------- - -Object detection is a common task in Computer Vision that aims to provide bounding box and class for each detected -object. We provide the class :py:class:`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO` to ease the management -of object detection results. Such input/output stores essential information in a list of -:py:class:`~ikomia.dataprocess.pydataprocess.CObjectDetection`: - -- unique identifier -- class label -- confidence -- box coordinates stored as list of 4 float numbers: [x-coordinate, y-coordinate, width, height] -- display color - -It also provides methods to fill and retrieve results (see -:py:class:`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO` for details). - -Usage as output: - -.. code-block:: python - - from ikomia.dataprocess import C2dImageTask, CObjectDetectionIO - - class MyDetectorPlugin(C2dImageTask): - - def __init__(self, name, param): - C2dImageTask.__init__(self, name) - # Add object detection output - self.add_output(CObjectDetectionIO()) - # Load class names - self.names = self.load_names() #to implement - # Generate class colors - self.colors = self.generate_colors() #to implement - - def run(self): - # Image input : - img_input = self.get_input(0) - src_image = img_input.get_image() - # Forward input image - self.forward_input_image(0, 0) - # Object detection output - obj_detect_out = self.get_output(1) - obj_detect_out.init("MyDetector", 0) - # Model prediction (to replace with your model inference) - output = self.model(src_image) - - # Process detections - index = 0 - for *xyxy, conf, cls in output: - # Box - w = float(xyxy[2] - xyxy[0]) - h = float(xyxy[3] - xyxy[1]) - obj_detect_out.add_object(index, self.names[int(cls)], conf.item(), - float(xyxy[0]), float(xyxy[1]), w, h, - self.colors[int(cls)]) - index += 1 - -.. note:: - In Ikomia Studio, :py:class:`~ikomia.dataprocess.pydataprocess.CObjectDetectionIO` output is displayed as graphics - layer on top of reference image (box + label + confidence) and as results table. - - -Instance segmentation I/O -------------------------- - -Instance segmentation is a common task in Computer Vision that aims to provide bounding box, class and mask for each -detected object (ie instance). We provide the class :py:class:`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO` -to ease the management of instance segmentation results. Such input/output stores essential information in a list of -:py:class:`~ikomia.dataprocess.pydataprocess.CInstanceSegmentation`: - -- unique identifier -- instance type (THING or STUFF) -- class index -- class label -- confidence -- box coordinates stored as list of 4 float numbers: [x-coordinate, y-coordinate, width, height] -- binary mask -- display color - -It also provides methods to fill and retrieve results (see -:py:class:`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO` for details). This input/output type is also suitable -for **panoptic segmentation**. - -Usage as output: - -.. code-block:: python - - from ikomia.dataprocess import C2dImageTask, CInstanceSegmentationIO - - class MySegmentorPlugin(C2dImageTask): - - def __init__(self, name, param): - C2dImageTask.__init__(self, name) - # Add object detection output - self.add_output(CInstanceSegmentationIO()) - # Load class names - self.names = self.load_names() #to implement - # Generate class colors - self.colors = self.generate_colors() #to implement - - def run(self): - # Image input : - img_input = self.get_input(0) - src_image = img_input.getImage() - h, w, c = src_image.shape - # Forward input image - self.forward_input_image(0, 0) - # Object detection output - instance_out = self.get_output(1) - instance_out.init("MySegmentor", 0, w, h) - # Model prediction (to replace with your model inference) - output = self.model(src_image) - - # Process detections - instances = outputs["instances"] - scores = instances.scores - boxes = instances.pred_boxes - classes = instances.pred_classes - masks = instances.pred_masks - - index = 0 - for box, score, cls, mask in zip(boxes, scores, classes, masks): - x1, y1, x2, y2 = box.numpy() - cls = int(cls.numpy()) - w = float(x2 - x1) - h = float(y2 - y1) - instance_out.add_instance(index, 0, cls, self.names[cls], float(score), - float(x1), float(y1), w, h, - mask.cpu().numpy().astype("uint8"), self.colors[cls+1]) - index += 1 - -.. note:: - In Ikomia Studio, :py:class:`~ikomia.dataprocess.pydataprocess.CInstanceSegmentationIO` output is displayed as graphics - layer on top of reference image (box + label + confidence), color mask overlay on reference image, merge mask of - all instances and results table. - - -Semantic segmentation I/O -------------------------- - -Semantic segmentation is a common task in Computer Vision that aims to provide mask where a class label value is set -for all pixels. We provide the class :py:class:`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO` -to ease the management of semantic segmentation results. Such input/output stores essential information as described -below: - -- Mask -- List of class names: index of a given class in this list corresponds to the pixel value in the mask -- List of colors (one for each class) - -It also provides methods to fill and retrieve results (see -:py:class:`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO` for details). - -Usage as output: - -.. code-block:: python - - from ikomia.dataprocess import C2dImageTask, CSemanticSegmentationIO - - class MySegmentorPlugin(C2dImageTask): - - def __init__(self, name, param): - C2dImageTask.__init__(self, name) - # Add object detection output - self.add_output(CSemanticSegmentationIO()) - # Load class names - self.names = self.load_names() #to implement - # Generate class colors - self.colors = self.generate_colors() #to implement - - def run(self): - # Image input : - img_input = self.get_input(0) - src_image = img_input.getImage() - # Forward input image - self.forward_input_image(0, 0) - # Object detection output - semantic_output = self.get_output(1) - # Model prediction (to replace with your model inference) - output = self.model(src_image) - - # Process detections - mask = outputs["sem_seg"].cpu().numpy() - - semantic_output.set_mask(mask) - semantic_output.set_class_names(self.names, self.colors) - - # Color mask overlay - self.set_output_color_map(0, 1, self.colors) - -.. note:: - In Ikomia Studio, :py:class:`~ikomia.dataprocess.pydataprocess.CSemanticSegmentationIO` output is displayed as a graylevel - mask, a color mask overlay on reference image and a legend image with the color/class mapping. \ No newline at end of file diff --git a/doc/source/plugin_parameters.rst b/doc/source/plugin_parameters.rst deleted file mode 100644 index 396310f6..00000000 --- a/doc/source/plugin_parameters.rst +++ /dev/null @@ -1,65 +0,0 @@ -Parameters management -===================== - -Core concept ------------- - -Algorithms often comes with parameters to adjust produced results. The Ikomia platform handles parameters in standalone class that will be shared across the process implementation and the UI widget. -Basically, this class must inherit :py:mod:`~ikomia.core.pycore.CWorkflowTaskParam` (C++ base class). It should include definition of your parameters variables as member and reimplement 2 methods: - -- :py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.set_values`: called when loading workflow from file or from Ikomia Studio internal database. It must set member variable values from a dict-like structure (key-value pairs). -- :py:meth:`~ikomia.core.pycore.CWorkflowTaskParam.get_values`: called when saving workflow in file or in Ikomia Studio internal database. It returns parameter keys and values as a dict-like structure. - -.. code-block:: python - - from ikomia import core - - class MyParam(core.CWorkflowTaskParam): - - def __init__(self): - core.CWorkflowTaskParam.__init__(self) - self.kernel_size = (3, 3) - self.sigma_x = 1.0 - self.sigma_y = 1.0 - - def set_values(self, params): - self.kernel_size = (int(params["kernel_size_x"]), int(params["kernel_size_y"])) - self.sigma_x = int(params["sigma_x"]) - self.sigma_y = int(params["sigma_y"]) - - def get_values(self): - params = {} - params["kernel_size_x"] = str(self.kernel_size[0]) - params["kernel_size_y"] = str(self.kernel_size[1]) - params["sigma_x"] = str(self.sigma_x) - params["sigma_y"] = str(self.sigma_y) - return params - - -.. important:: the dict-like structure handles only **str** type for both key and value. Thus, one should take care to set valid conversion from the original parameter type (int, float, bool...) to str. - - -Inherit from the pure Python base class ---------------------------------------- - -As an option, it is possible to inherit your parameter class from a pure Python base class -(:py:mod:`~ikomia.core.task.TaskParam`) that make it easier. Indeed, parameters are managed directly -in a dict member instead of defining one variable for each parameter. Another small advantage is that -the method *get_parametersMap()* has not to be reimplemented anymore. - -.. code-block:: python - - from ikomia.core.task import TaskParam - - class MyParam(TaskParam): - - def __init__(self): - core.TaskParam.__init__(self) - self.cfg["kernel_size"] = (3, 3) - self.cfg["sigma_x"] = 1.0 - self.cfg["sigma_y"] = 1.0 - - def set_values(self, params): - self.cfg["kernel_size"] = (int(params["kernel_size_x"]), int(params["kernel_size_y"])) - self.cfg["sigma_x"] = int(params["sigma_x"]) - self.cfg["sigma_y"] = int(params["sigma_y"]) diff --git a/doc/source/plugin_task.rst b/doc/source/plugin_task.rst deleted file mode 100644 index fc1a05e3..00000000 --- a/doc/source/plugin_task.rst +++ /dev/null @@ -1,155 +0,0 @@ -Task management -=============== - -In Ikomia platform, a task is the implementation of a specific algorithm. We use inheritance to set a -functional framework and simplify customization. Basically, any new Ikomia plugin must implement a -task class derived from the base class :py:mod:`~ikomia.core.pycore.CWorkflowTask` or from a -specialization class which itself inherits from this base class. - -- :ref:`Mandatory methods` -- :ref:`Recommended methods` -- :ref:`Metadata` - - -Mandatory methods to implement ------------------------------- - -- **Constructor**: base class contructor must be called explicitly. This is also the place where you define inputs and outputs. - -.. code-block:: python - - class MyAlgorithm(dataprocess.CWorkflowTask): - - def __init__(self, name, param): - dataprocess.CWorkflowTask.__init__(self, name) - # Add image input - self.add_output(dataprocess.CImageIO()) - # Add graphics output - self.add_output(dataprocess.CGraphicsOutput()) - # Add numeric output - self.add_output(dataprocess.CNumericIO()) - -- **run()**: launch the algorithm execution. When the method is called, inputs data are set and ready to process. The method must begin with a call to **begin_task_run()** and end with a call to **end_task_run()**. In the code snippet below, you will find the most useful methods that you will need while implementing your own plugin: - -.. code-block:: python - - class MyAlgorithm(dataprocess.CWorkflowTask): - - def run(self): - - # Execution initialization - self.begin_task_run() - - # Get inputs - input1 = self.get_input(0) - input2 = self.get_input(1) - - # Get parameters - param = self.get_param_object() - - # Get outputs - output1 = self.get_output(0) - output1 = self.get_output(1) - - # Execution finalization - self.end_task_run() - -.. note:: See :py:mod:`~ikomia.core.pycore.CWorkflowTask` to have details around all available methods. - - -Recommended methods to implement --------------------------------- - -- **get_progress_steps()**: Ikomia Studio only. For time consuming algorithms, it could be relevant to split execution into separate parts and give progression feedback after each part (if possible). If so, you have to first implement this method and return the number of execution parts. Then, in your **run()** method, you have to place a call to **self.emit_step_progress()** after each part to notify the main progress bar of Ikomia Studio. -- **stop()**: method called when a user requests the process to stop. For time consuming algorithm it's highly recommended to integrate a stop mechanism inside your algorithm execution code. This method is somehow just a callback. - - -Available specializations -------------------------- - -To ease implementation of common image processing tasks, we provide some specialization classes from -which you can inherit. They integrate useful features to speed your development. - - -Simple image processing algorithms -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask` : base class dedicated to algorithms processing image and producing at least a result image. - - - Inputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`) and graphics (:py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsInput`). - - Outputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`). - - Important features: - - create binary mask from graphics. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.create_graphics_mask`. - - apply a binary mask to the desired output image so that only masked areas are processed. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.apply_graphics_mask` and :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.apply_graphics_mask_to_binary`. - - forward input image to the desired output without modification: :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.forward_input_image`. - - attach a color overlay mask to the desired output (Ikomia Studio only). See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageTask.set_output_color_map`. - -.. note:: If any of these features are useful for your own algorithm, inherit your class from this base class instead of CWorkflowTask. Please consult :doc:`this tutorial ` for details. - - -Interactive image processing algorithms -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask`: choose it as a base class -if you need user interaction for your algorithm. The class embeds a graphics interaction layer. -Every changes made by users on this layer are notified and corresponding actions can be implemented. -**Ikomia Studio only**. - - - Inputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`) and graphics (:py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsInput`). - - Outputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`). - - Important features: - - callback to manage interaction layer modification. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask.graphics_changed`. - - create binary mask from the graphics interaction layer. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask.create_interaction_mask`. - - compute connected components from the binary mask generated from the interaction layer. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask.compute_blobs`. - - get connected components as a list of polygons (list of points). See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask.get_blobs`. - - clear interaction layer. See :py:meth:`~ikomia.dataprocess.pydataprocess.C2dImageInteractiveTask.clear_interaction_layer`. - -.. note:: If any of these features are useful for your own algorithm, inherit your class from this base class instead of CWorkflowTask. - - -Video processing algorithms -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:py:class:`~ikomia.dataprocess.pydataprocess.CVideoTask`: choose it as a base class -if your algorithm is dedicated to video or stream. The class inherits from -:py:class:`~ikomia.dataprocess.pydataprocess.C2dImageTask` adding only a mechanism to handle -start and stop events. - - - Inputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`) and graphics (:py:mod:`~ikomia.dataprocess.pydataprocess.CGraphicsInput`). - - Outputs: image (:py:mod:`~ikomia.dataprocess.pydataprocess.CImageIO`). - - Important features: - - callback to manage video start event. See :py:meth:`~ikomia.dataprocess.pydataprocess.CVideoTask.notify_video_start`. - - callback to manage video stop event. See :py:meth:`~ikomia.dataprocess.pydataprocess.CVideoTask.notify_video_stop`. - -.. note:: Please consult source code of `infer_raft_optical_flow `_ for implementation example. - - -Deep Learning training algorithms -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:py:class:`~ikomia.dnn.dnntrain.TrainProcess`: choose it as a base class for any deep learning -training algorithms. This base class integrated training monitoring features for **MLflow** and -**Tensorboard**. - - - Inputs: Ikomia dataset (:py:mod:`~ikomia.dnn.datasetio.IkDatasetIO`). - - Outputs: None - - Important features: - - MLflow: a local tracking server is automatically started and ready to use at http://localhost:5000. By default, logging data are saved in the Ikomia folder in *mlflow* subdirectory. The class offers a thin wrapper to access logging methods: model hyper-parameters with :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_param` and :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_params`, model metrics with :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_metric` and :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_metrics` and model artifacts with :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_artifact` and :py:meth:`~ikomia.dnn.dnntrain.TrainProcess.log_artifacts`. - - Tensorboard: a local tracking server is automatically started and ready to use at http://localhost:6006. By default, logging data are saved in the Ikomia folder in *tensorboard* subdirectory. Use classic Tensorboard functions to log your data. - -.. note:: Please consult source code of `train_yolov5 `_ for implementation example. - - -Metadata --------- - -Ikomia platform allows you to add additionnal information to your plugin. This will help users to -know more about your algorithm and give essential visual elements in Ikomia HUB. - -These information are store in a factory class inherited from :py:class:`~ikomia.dataprocess.pydataprocess.CTaskFactory`. -It aims to create instance of your process class. Plugin metadata are set in the constructor within the **CTaskInfo** member variable. -You will find he full list of information in the :py:class:`~ikomia.dataprocess.pydataprocess.CTaskInfo` documentation. - -For Ikomia Studio, you can customize the documentation page of your plugin. It can be interesting if you want to put more -information than the provided fields. You just need to place your documentation page in the root folder of the plugin. -File format can be either Markdown or HTML. Ikomia Studio will automatically search for files with the following names: -*doc.md, doc.html, doc.htm, documentation.md, documentation.html, documentation.htm, info.md, info.html, info.htm*. diff --git a/doc/source/python_env.rst b/doc/source/python_env.rst deleted file mode 100644 index 1c79084e..00000000 --- a/doc/source/python_env.rst +++ /dev/null @@ -1,74 +0,0 @@ -Python environment -================== - -Version -------- - -Ikomia software comes with its own Python environment, -completely independant of the one you may install system-wide. -In case of multi-users machine, Ikomia installs one Python environment per user. -Initially, only required packages are already installed. -The Python environment configuration may vary among your operating system: - -**Windows 10** - -- Version: *3.8* -- Path: *c:\\Users\\{username}\\Ikomia\\Python* -- Installed packages: *pip, numpy=1.20.0, requests, PyQt5=5.15.2, Pillow=8.1.0, opencv=4.5.2, mlflow=1.14.1, tensorboard>=2.4.1, matplotlib* - -**Linux** - -- Version: *3.7* -- Path: *~/Ikomia/Python* -- Installed packages: *pip, numpy=1.20.0, requests, PyQt5=5.15.2, Pillow=8.1.0, opencv=4.5.2, mlflow=1.14.1, tensorboard>=2.4.1, matplotlib* - -.. Note:: To ensure interoperability with Qt, the PyQt5 package **must not** be updated with pip or other package manager. - -Package management ------------------- - -**pip** - -As it is a standalone Python environment, you can manage your packages with pip and all its features. - -Windows - -.. code-block:: bash - - cd c:\Users\{username}\Ikomia\Python - python.exe -m pip install {your_package} - -Linux - -.. code-block:: bash - - cd ~/Ikomia/Python/bin - ./python37m -m pip install {your_package} - - -**Ikomia Plugin Manager** - -Ikomia includes a specific module to manage your packages from the GUI: - -- The left table shows the list of all your plugins (a plugin in red means a missing dependency). -- The right table shows the list of the selected plugin dependencies (name, version and last version available). - -Then you can select a package and make the following actions: - -- Install missing package. -- Update package to the latest version. - - -.. image:: _static/plugin_manager.jpg - - -OpenCV ------- - -A GPU-enabled version of OpenCV is bundled within the Ikomia Studio Python environment. It includes all the core -and contribution librairies with CUDA support. There is only one important constraint to respect, **you must import Ikomia -module before importing cv2 module**. - -.. Important:: - Because Python OpenCV is already included, the package *opencv-python* from Pypi repository must not be installed in - the Ikomia Python environment. This will lead to incompatibility issues. diff --git a/doc/source/release_notes/index.md b/doc/source/release_notes/index.md new file mode 100644 index 00000000..85e2828d --- /dev/null +++ b/doc/source/release_notes/index.md @@ -0,0 +1,60 @@ +# Release Notes + +Version history of the Ikomia API. + +
+ 0.9.0 + +
+ +
+ 0.8.1 + +___ +**Improvements**: +- Timeout support while writing videos +- Add Python bindings for executeActions() for classes inheriting ikomia.core.CWorkflowTask +- Add download method in ikomia.core.CWorkflowTask +- Improve logging system +- Update and fix documentation +- Let training task starts if Tensorboard initialization failed + +**Bug fixes**: +- Manage invalid ID passed to ikomia.dataprocess.CWorkflow.getTask() +- Fix legend image for semantic segmentation output +- Auto-completion process skip invalid plugins +- ... +___ +
+ +
+ 0.8.0 + +___ +**New features**: +- New algorithms from the Ikomia HUB: YoloV7, Open MMlab object detection, SparseInst (training and inference) +- Add filtering tasks for object detection, instance segmentation and semantic segmentation +- Add display for text data (Python data dict output for example) +- Add feature to blacklist Python packages that confict with Ikomia built-in packages +- Manage new workflow I/O: object detection, instance segmentation, semantic segmentation +- Add automatic I/O conversion between different types (ex: object detection output -> graphics input) + + +**Improvements**: +- Manage compilation architecture for C++ algorithms from Ikomia HUB + + +**Bug fixes**: +- Disable Tensorboard auto-start to avoid algorithm installation failure +- ... +___ +___ +
+ +* 0.7.0 +* 0.6.1 +* 0.6.0 +* 0.5.0 +* 0.4.1 +* 0.4.0 +* 0.3.0 diff --git a/doc/source/tutorials/how_to_on_stream.md b/doc/source/tutorials/how_to_on_stream.md new file mode 100644 index 00000000..c5282690 --- /dev/null +++ b/doc/source/tutorials/how_to_on_stream.md @@ -0,0 +1,207 @@ +# First Steps with Camera Stream Processing with Ikomia + +Camera stream processing refers to the real-time analysis and manipulation of images and video streams captured from a camera. +This technique is widely used in various applications, such as computer vision, surveillance, robotics, and entertainment, among others. + +In computer vision, camera stream processing is used for object detection and recognition, face detection, motion tracking, and image segmentation. + +In **surveillance**, camera stream processing is used for detecting anomalies and events, such as intrusion detection and crowd behavior analysis. + +In **robotics**, camera stream processing is used for autonomous navigation, object detection, and obstacle avoidance. + +In **entertainment**, camera stream processing is used for augmented reality, virtual reality, and gesture recognition. + +Overall, camera stream processing plays a crucial role in various fields and enables many exciting applications that were once considered impossible. + +To get started with camera stream processing, we will use OpenCV and `VideoCapture`. + +```{warning} +In this part, you need to be familiar with Ikomia Workflow. + +Please read the [Getting Started](../getting_started) and [Going deeper with worflows](../advanced_guide/index) before this tutorial. +``` + +## Process Stream from your Webcam + +### Test your Webcam without Ikomia Workflow + +Start by testing your webcam with the following code : +```python +from ikomia.utils.displayIO import display +import cv2 + +stream = cv2.VideoCapture(0) + +while True: + # Read image from stream + ret, frame = stream.read() + + # Test if streaming is OK + if not ret: + continue + + # Display image with OpenCV + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + display(frame, viewer="opencv", title="Ikomia Demo") + + # Press 'q' to quit the streaming process + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +# After the loop release the stream object +stream.release() +# Destroy all windows +cv2.destroyAllWindows() +``` +In this code, we used `cv2.cvtColor()` because OpenCV reads images as BGR (Blue, Red, Green) buffers whereas Ikomia needs RGB images. + +### Basic Process with Ikomia Workflow + +We introduce Ikomia Workflow in the process and we integrate color conversion directly in the workflow. + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display +import cv2 + +stream = cv2.VideoCapture(0) + +# Init the workflow +wf = Workflow() + +# Add color conversion to workflow +cvt = wf.add_task(ik.ocv_color_conversion(code=str(cv2.COLOR_BGR2RGB)), auto_connect=True) + +while True: + # Read image from stream + ret, frame = stream.read() + + # Test if streaming is OK + if not ret: + continue + + # Run workflow on image + wf.run_on(frame) + + # Display results from "cvt" + display(cvt.get_output(0).get_image(), title="Demo", viewer="opencv") + + # Press 'q' to quit the streaming process + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +# After the loop release the stream object +stream.release() +# Destroy all windows +cv2.destroyAllWindows() +``` + +### Face detection + +We just add a face detector to the workflow and display the corresponding results. + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display +import cv2 + +stream = cv2.VideoCapture(0) + +# Init the workflow +wf = Workflow() + +# Add color conversion +cvt = wf.add_task(ik.ocv_color_conversion(code=str(cv2.COLOR_BGR2RGB)), auto_connect=True) + +# Add face detection +face = wf.add_task(ik.infer_face_detection_kornia(conf_thres="0.8"), auto_connect=True) + +while True: + ret, frame = stream.read() + + # Test if streaming is OK + if not ret: + continue + + # Run workflow on image + wf.run_on(frame) + + # Display results from "face" + display(face.get_image_with_graphics(), title="Demo", viewer="opencv") + + # Press 'q' to quit the streaming process + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +# After the loop release the stream object +stream.release() +# Destroy all windows +cv2.destroyAllWindows() +``` + +### Blurring Face Detection + +We just add a blurring algorithm for each detected face and display the corresponding results. + +```python +from ikomia.dataprocess.workflow import Workflow +from ikomia.utils import ik +from ikomia.utils.displayIO import display +import cv2 + +stream = cv2.VideoCapture(0) + +# Init the workflow +wf = Workflow() + +# Add color conversion +cvt = wf.add_task(ik.ocv_color_conversion(code=str(cv2.COLOR_BGR2RGB)), auto_connect=True) + +# Add face detection +face = wf.add_task(ik.infer_face_detection_kornia(conf_thres="0.8"), auto_connect=True) + +# Add face blurring +blur = wf.add_task(ik.ocv_stack_blur(kSizeHeight="61", kSizeWidth="61"), auto_connect=True) + +while True: + ret, frame = stream.read() + + # Test if streaming is OK + if not ret: + continue + + # Run workflow on image + wf.run_on(frame) + + # Display results from "face" and "blur" + display(face.get_image_with_graphics(), title="Demo Face Detection", viewer="opencv") + display(blur.get_output(0).get_image(), title="Demo Blurry Face Detection", viewer="opencv") + + # Press 'q' to quit the streaming process + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +# After the loop release the stream object +stream.release() +# Destroy all windows +cv2.destroyAllWindows() +``` + +## Troubleshooting Tips + +Here are some common errors that users may encounter when processing camera streams, along with some troubleshooting tips: + +1. **"Error opening video capture device"**: This error occurs when the video capture device cannot be opened. This could be due to the device being busy or not connected properly. Make sure that the device is connected and try restarting the application. +2. **"Unable to retrieve frame"**: This error occurs when the application is unable to retrieve frames from the video capture device. This could be due to the device being busy or not connected properly. Make sure that the device is connected and try restarting the application. +3. **"Memory allocation error"**: This error occurs when the application is unable to allocate memory for image processing. This could be due to insufficient memory on the system. Try closing other applications to free up memory. + +If you encounter any other errors or issues, try searching for solutions online or consulting the documentation for the specific library or application you are using. + +## Resources + +- [OpenCV documentation](https://docs.opencv.org/master/) +- [OpenCV tutorials](https://docs.opencv.org/master/d9/df8/tutorial_root.html) +- [VideoCapture documentation](https://docs.opencv.org/master/d8/dfe/classcv_1_1VideoCapture.html) + diff --git a/doc/source/working_with_task.rst b/doc/source/working_with_task.rst deleted file mode 100644 index bdf95180..00000000 --- a/doc/source/working_with_task.rst +++ /dev/null @@ -1,107 +0,0 @@ -Working with tasks -================== - -The recommended way to apply algorithms with Ikomia API is through the :py:mod:`~ikomia.dataprocess.workflow` module. -However, you have also access to algorithm at task level with the possibility to run it independently. - - -Run task without workflow -------------------------- - -The example below illustrates the steps to run a single algorithm. - -.. code-block:: python - - from ikomia.core import task - from ikomia.utils import ik - - # Instanciate algorithm - box_filter = task.create(ik.ocv_box_filter) - - # Set input(s) - img = cv2.imread("path/to/image.png") - img_input = box_filter.get_input(0) - img_input.set_image(img) - - # Run - box_filter.run() - -Consult :py:meth:`~ikomia.core.task.create`, :py:meth:`~ikomia.core.pycore.CWorkflowTask.get_input` and -:py:meth:`~ikomia.core.pycore.CWorkflowTask.run` for details. - - -Manage parameters ------------------ - -Algorithm behavior can be adjusted by setting task parameters (:py:meth:`~ikomia.core.pycore.CWorkflowTask.set_parametersValues`). - -.. code-block:: python - - from ikomia.core import task - from ikomia.utils import ik - - # Instanciate algorithm - box_filter = task.create(ik.ocv_box_filter) - - # ... - - # Set parameters - box_filter_params = { - ik.ocv_box_filter_param.kSizeHeight: 11, - ik.ocv_box_filter_param.kSizeWidth: 11 - } - box_filter.set_parameters(box_filter_params) - - # Run - box_filter.run() - - -Manage inputs/outputs ---------------------- - -Inputs -^^^^^^ - -From a task object instance, you access inputs with :py:meth:`~ikomia.core.pycore.CWorkflowTask.get_input`. -Depending on algorithm, inputs can be of various type. Please consult this :doc:`page` to have more -information about possible input types. - -Outputs -^^^^^^^ - -Like for workflows, the :py:mod:`~ikomia.core.task` module provides useful functions to get common output types: - -- :py:meth:`~ikomia.core.task.get_image_output` -- :py:meth:`~ikomia.core.task.get_graphics_output` -- :py:meth:`~ikomia.core.task.get_numeric_output` -- :py:meth:`~ikomia.core.task.get_data_string_output` -- :py:meth:`~ikomia.core.task.get_blob_measure_output` -- :py:meth:`~ikomia.core.task.get_dataset_output` -- :py:meth:`~ikomia.core.task.get_array_output` -- :py:meth:`~ikomia.core.task.get_path_output` - -Here is a example with image output: - -.. code-block:: python - - from ikomia.core import task - from ikomia.utils import ik - - # Instanciate algorithm - box_filter = task.create(ik.ocv_box_filter) - - # Set input(s) - img = cv2.imread("path/to/image.png") - img_input = box_filter.get_input(0) - img_input.set_image(img) - - # Run - box_filter.run() - - # Get output - img_out = task.get_image_output(box_filter) - cv2.imshow("Box Filter result", img_out.getImage()) - -.. note:: - We provide high-level function to handle image and graphics outputs. Thus you can compute the merge image (for visualization) between graphics and image - outputs (:py:meth:`~ikomia.core.task.get_image_with_graphics`). \ No newline at end of file