diff --git a/examples/annotation_import/image.ipynb b/examples/annotation_import/image.ipynb index f39e70c68..9695e574c 100644 --- a/examples/annotation_import/image.ipynb +++ b/examples/annotation_import/image.ipynb @@ -39,7 +39,7 @@ "source": [ "# Image Annotation Import\n", "* This notebook will provide examples of each supported annotation type for image assets. It will cover the following:\n", - " * Model-assisted labeling - used to provide pre-annotated data for your labelers. This will enable a reduction in the total amount of time to properly label your assets. Model-assisted labeling does not submit the labels automatically, and will need to be reviewed by a labeler for submission.\n", + " * Model-Assisted Labeling (MAL) - used to provide pre-annotated data for your labelers. This will enable a reduction in the total amount of time to properly label your assets. Model-assisted labeling does not submit the labels automatically, and will need to be reviewed by a labeler for submission.\n", " * Label Import - used to provide ground truth labels. These can in turn be used and compared against prediction labels, or used as benchmarks to see how your labelers are doing." ] }, @@ -78,12 +78,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "4d63074b-2379-48af-b9d6-2a66190f03c4", "metadata": { - "id": "4d63074b-2379-48af-b9d6-2a66190f03c4" + "id": "4d63074b-2379-48af-b9d6-2a66190f03c4", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "2560882d-6542-4dda-c075-d197ef2da5e3" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[K |████████████████████████████████| 172 kB 9.3 MB/s \n", + "\u001b[K |████████████████████████████████| 6.3 MB 15.2 MB/s \n", + "\u001b[?25h Building wheel for pygeotile (setup.py) ... \u001b[?25l\u001b[?25hdone\n" + ] + } + ], "source": [ "!pip install -q 'labelbox[data]'" ] @@ -134,24 +148,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 30, "id": "86003724-4807-4281-95c1-5284a6f9609f", "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "86003724-4807-4281-95c1-5284a6f9609f", - "outputId": "d6af46bd-128b-4bd2-9aec-ad2188a8df06" + "id": "86003724-4807-4281-95c1-5284a6f9609f" }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:labelbox.client:Initializing Labelbox client at 'https://api.labelbox.com/graphql'\n" - ] - } - ], + "outputs": [], "source": [ "# Add your api key\n", "API_KEY = None\n", @@ -192,9 +194,21 @@ "We will be creating two projects, one for model-assisted labeling, and one for label imports" ] }, + { + "cell_type": "markdown", + "source": [ + "First, we create an ontology with all the possible tools and classifications supported for images. The official list of supported annotations to import can be found here:\n", + "- [Model-Assisted Labeling](https://docs.labelbox.com/docs/model-assisted-labeling) (annotations/labels are not submitted)\n", + "- [Ground Truth](https://docs.labelbox.com/docs/import-ground-truth) (annotations/labels are submitted)" + ], + "metadata": { + "id": "49i_juOUr6av" + }, + "id": "49i_juOUr6av" + }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 31, "id": "f9f9287c-aad7-4914-bc87-1453fb8bce81", "metadata": { "id": "f9f9287c-aad7-4914-bc87-1453fb8bce81" @@ -202,47 +216,84 @@ "outputs": [], "source": [ "ontology_builder = OntologyBuilder(\n", - " tools=[\n", - " Tool(tool=Tool.Type.BBOX, name=\"box\"),\n", - " Tool(tool=Tool.Type.LINE, name=\"line\"),\n", - " Tool(tool=Tool.Type.POINT, name=\"point\"),\n", - " Tool(tool=Tool.Type.POLYGON, name=\"polygon\"), \n", - " Tool(tool=Tool.Type.SEGMENTATION, name=\"mask\")],\n", - " classifications=[\n", - " Classification(class_type=Classification.Type.TEXT, instructions=\"text\"),\n", - " Classification(class_type=Classification.Type.CHECKLIST, instructions=\"checklist\", options=[\n", - " Option(value=\"first_checklist_answer\"),\n", - " Option(value=\"second_checklist_answer\") \n", - " ]),\n", - " Classification(class_type=Classification.Type.RADIO, instructions=\"radio\", options=[\n", - " Option(value=\"first_radio_answer\"),\n", - " Option(value=\"second_radio_answer\")\n", - " ]), \n", - "])\n" + " tools=[ # List of Tool objects\n", + " Tool( # Bounding Box tool given the name \"box\"\n", + " tool=Tool.Type.BBOX, \n", + " name=\"box\"), \n", + " Tool( # Polyline tool given the name \"line\"\n", + " tool=Tool.Type.LINE, \n", + " name=\"line\"), \n", + " Tool( # Point tool given the name \"point\"\n", + " tool=Tool.Type.POINT, \n", + " name=\"point\"), \n", + " Tool( # Polygon tool given the name \"polygon\"\n", + " tool=Tool.Type.POLYGON, \n", + " name=\"polygon\"), \n", + " Tool( # Segmentation mask tool given the name \"mask\"\n", + " tool=Tool.Type.SEGMENTATION, \n", + " name=\"mask\")], \n", + " classifications=[ # List of Classification objects\n", + " Classification( # Text classification given the name \"text\"\n", + " class_type=Classification.Type.TEXT,\n", + " instructions=\"text\"), \n", + " Classification( # Checklist classification given the name \"text\" with two options: \"first_checklist_answer\" and \"second_checklist_answer\"\n", + " class_type=Classification.Type.CHECKLIST, \n", + " instructions=\"checklist\", \n", + " options=[\n", + " Option(value=\"first_checklist_answer\"),\n", + " Option(value=\"second_checklist_answer\") \n", + " ]\n", + " ), \n", + " Classification( # Radio classification given the name \"text\" with two options: \"first_radio_answer\" and \"second_radio_answer\"\n", + " class_type=Classification.Type.RADIO, \n", + " instructions=\"radio\", \n", + " options=[\n", + " Option(value=\"first_radio_answer\"),\n", + " Option(value=\"second_radio_answer\")\n", + " ]\n", + " )\n", + " ]\n", + ")" ] }, + { + "cell_type": "markdown", + "source": [ + "To show the two different ways to upload annotations, we create two projects - one to showcase MAL (Model-Assisted Labeling) and one to showcase Label Import." + ], + "metadata": { + "id": "1GdimALBuzRU" + }, + "id": "1GdimALBuzRU" + }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 32, "id": "044e9194-d21d-403e-b64c-047c1063b0fe", "metadata": { "id": "044e9194-d21d-403e-b64c-047c1063b0fe" }, "outputs": [], "source": [ + "# Create two Labelbox projects\n", "mal_project = client.create_project(name=\"image_mal_project\")\n", "li_project = client.create_project(name=\"image_label_import_project\")\n", "\n", + "# Create one Labelbox dataset\n", "dataset = client.create_dataset(name=\"image_annotation_import_demo_dataset\")\n", + "\n", + "# Grab an example image and create a Labelbox data row\n", "test_img_url = \"https://raw.githubusercontent.com/Labelbox/labelbox-python/develop/examples/assets/2560px-Kitano_Street_Kobe01s5s4110.jpg\"\n", "data_row = dataset.create_data_row(row_data=test_img_url)\n", - "editor = next(client.get_labeling_frontends(where=LabelingFrontend.name == \"Editor\"))\n", "\n", - "mal_project.setup(editor, ontology_builder.asdict())\n", - "mal_project.datasets.connect(dataset)\n", + "# Setup your ontology / labeling editor\n", + "editor = next(client.get_labeling_frontends(where=LabelingFrontend.name == \"Editor\")) # Unless using a custom editor, do not modify this\n", "\n", - "li_project.setup(editor, ontology_builder.asdict())\n", - "li_project.datasets.connect(dataset)" + "mal_project.setup(editor, ontology_builder.asdict()) # Connect your ontology and editor to your MAL project\n", + "mal_project.datasets.connect(dataset) # Connect your dataset to your MAL project\n", + "\n", + "li_project.setup(editor, ontology_builder.asdict()) # Connect your ontology and editor to your Label Import project\n", + "li_project.datasets.connect(dataset) # Connect your dataset to your Label Import project" ] }, { @@ -268,28 +319,57 @@ }, { "cell_type": "code", - "execution_count": 9, - "id": "d468b0d0-e7d8-42d9-81fd-3db7c67d7b83", + "source": [ + "point_annotation=ObjectAnnotation(\n", + " value=Point(x=882,y=159), # Coordinates for this point annotation\n", + " name=\"point\" # Name of the tool in your ontology\n", + ")\n", + "\n", + "box_annotation=ObjectAnnotation(\n", + " value=Rectangle( # Coordinates for the top-left and bottom-right points of your bounding box, respectively\n", + " start=Point(x=557,y=898),\n", + " end=Point(x=852,y=1140)\n", + " ),\n", + " name=\"box\" # Name of the tool in your ontology\n", + ")\n", + "\n", + "polyline_annotation=ObjectAnnotation(\n", + " value=Line( # Coordinates for the keypoints in your polyline\n", + " points=[Point(x=2534.353, y=249.471),Point(x=2429.492, y=182.092),Point(x=2294.322, y=221.962),Point(x=2224.491, y=180.463),Point(x=2136.123, y=204.716),\n", + " Point(x=1712.247, y=173.949),Point(x=1703.838, y=84.438),Point(x=1579.772, y=82.61),Point(x=1583.442, y=167.552),\n", + " Point(x=1478.869, y=164.903),Point(x=1418.941, y=318.149),Point(x=1243.128, y=400.815),Point(x=1022.067, y=319.007),\n", + " Point(x=892.367, y=379.216),Point(x=670.273, y=364.408),Point(x=613.114, y=288.16),Point(x=377.559, y=238.251),\n", + " Point(x=368.087, y=185.064),Point(x=246.557, y=167.286),Point(x=236.648, y=285.61),Point(x=90.929, y=326.412)]\n", + " ),\n", + " name=\"line\" # Name of the tool in your ontology\n", + ")\n", + "\n", + "polygon_annotation=ObjectAnnotation(\n", + " value=Polygon( # Coordinates for the verticies of your polygon\n", + " points=[Point(x=1489.581,y=183.934),Point(x=2278.306,y=256.885),Point(x=2428.197,y=200.437),Point(x=2560.0,y=335.419),\n", + " Point(x=2557.386,y=503.165),Point(x=2320.596,y=503.103),Point(x=2156.083, y=628.943),Point(x=2161.111,y=785.519),\n", + " Point(x=2002.115, y=894.647),Point(x=1838.456,y=877.874),Point(x=1436.53,y=874.636),Point(x=1411.403,y=758.579),\n", + " Point(x=1353.853,y=751.74),Point(x=1345.264, y=453.461),Point(x=1426.011,y=421.129)]\n", + " ),\n", + " name=\"polygon\" # Name of the tool in your ontology\n", + ")\n", + "\n", + "mask_annotation=ObjectAnnotation(\n", + " value=Mask( # Numpy array representation of a segmentation mask with the corresponding values within the array that represent the segmentation mask\n", + " mask=MaskData(\n", + " arr=np.zeros([400,450,3],dtype='uint8') # Creating an example numpy array to represent a mask creating a square from pixels 0,0 to 128,128\n", + " ),\n", + " color=(0,0,0) # Identifying what values in the numpy array correspond to the mask annotation (since I made a 3-D array with all zeroes, here it's 0,0,0)\n", + " ),\n", + " name=\"mask\" # Name of the tool in your ontology\n", + ")" + ], "metadata": { - "id": "d468b0d0-e7d8-42d9-81fd-3db7c67d7b83" + "id": "qzBqhV4Pv3yp" }, - "outputs": [], - "source": [ - "def create_objects():\n", - " point = Point(x=100,y=100)\n", - " point_annotation = ObjectAnnotation(value=point, name=\"point\")\n", - " rectangle = Rectangle(start=Point(x=30,y=30), end=Point(x=200,y=200))\n", - " rectangle_annotation = ObjectAnnotation(value=rectangle, name=\"box\")\n", - " line = Line(points=[Point(x=60,y=70), Point(x=65,y=100), Point(x=80,y=130), Point(x=40,y=200)])\n", - " line_annotation = ObjectAnnotation(value=line, name=\"line\")\n", - " array = np.zeros([128, 128, 3], dtype=np.uint8)\n", - " polygon = Polygon(points=[Point(x=100,y=100), Point(x=110,y=110), Point(x=130,y=130), Point(x=170,y=170), Point(x=220,y=220)])\n", - " polygon_annotation = ObjectAnnotation(value=polygon, name=\"polygon\")\n", - " mask_data = MaskData(arr=array)\n", - " mask = Mask(mask=mask_data, color=(0, 0, 0))\n", - " mask_annotation = ObjectAnnotation(value=mask, name=\"mask\")\n", - " return point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation" - ] + "id": "qzBqhV4Pv3yp", + "execution_count": 33, + "outputs": [] }, { "cell_type": "markdown", @@ -303,22 +383,39 @@ }, { "cell_type": "code", - "execution_count": 10, - "id": "e1a03976-4e50-4d10-b7ad-1a83ccc51a2a", + "source": [ + "text_annotation=ClassificationAnnotation(\n", + " value=Text( # String value for the text annotation\n", + " answer=\"the answer to the text question\" \n", + " ), \n", + " name=\"text\" # Name of the classification in your ontology\n", + ")\n", + "\n", + "checklist_annotation=ClassificationAnnotation(\n", + " value=Checklist(\n", + " answer=[ # List of the checklist answers in your ontology\n", + " ClassificationAnswer(name=\"first_checklist_answer\"),\n", + " ClassificationAnswer(name=\"second_checklist_answer\")\n", + " ]\n", + " ), \n", + " name=\"checklist\" # Name of the classification in your ontology\n", + ")\n", + "\n", + "radio_annotation=ClassificationAnnotation(\n", + " value=Radio(\n", + " answer=ClassificationAnswer(\n", + " name=\"second_radio_answer\" # Name of the radio answer in your ontology\n", + " )\n", + " ), \n", + " name=\"radio\" # Name of the classification in your ontology\n", + ")" + ], "metadata": { - "id": "e1a03976-4e50-4d10-b7ad-1a83ccc51a2a" + "id": "f2RtQQPCymOB" }, - "outputs": [], - "source": [ - "def create_classifications():\n", - " text = Text(answer=\"the answer to the text question\")\n", - " text_annotation = ClassificationAnnotation(value=text, name=\"text\")\n", - " checklist = Checklist(answer=[ClassificationAnswer(name=\"first_checklist_answer\"),ClassificationAnswer(name=\"second_checklist_answer\")])\n", - " checklist_annotation = ClassificationAnnotation(value=checklist, name=\"checklist\")\n", - " radio = Radio(answer = ClassificationAnswer(name = \"second_radio_answer\"))\n", - " radio_annotation = ClassificationAnnotation(value=radio, name=\"radio\")\n", - " return checklist_annotation, radio_annotation, text_annotation" - ] + "id": "f2RtQQPCymOB", + "execution_count": 34, + "outputs": [] }, { "cell_type": "markdown", @@ -332,24 +429,33 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 35, "id": "6d72fe25-ff7e-4e0a-94cf-095e4df73da0", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "6d72fe25-ff7e-4e0a-94cf-095e4df73da0", - "outputId": "95970a0c-bb5f-4966-bfac-905de8c23374" + "outputId": "f9447913-c3ea-40c6-c1a4-449640add743" }, "outputs": [ { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.7/dist-packages/labelbox/data/annotation_types/classification/classification.py:85: UserWarning: Dropdown classification is deprecated and will be removed in a future release\n", + " warnings.warn(\"Dropdown classification is deprecated and will be \"\n" + ] + }, + { + "output_type": "execute_result", "data": { "text/plain": [ - "{'annotations': [ObjectAnnotation(name='point', feature_schema_id=None, extra={}, value=Point(extra={}, x=100.0, y=100.0), classifications=[]),\n", - " ObjectAnnotation(name='box', feature_schema_id=None, extra={}, value=Rectangle(extra={}, start=Point(extra={}, x=30.0, y=30.0), end=Point(extra={}, x=200.0, y=200.0)), classifications=[]),\n", - " ObjectAnnotation(name='line', feature_schema_id=None, extra={}, value=Line(extra={}, points=[Point(extra={}, x=60.0, y=70.0), Point(extra={}, x=65.0, y=100.0), Point(extra={}, x=80.0, y=130.0), Point(extra={}, x=40.0, y=200.0)]), classifications=[]),\n", - " ObjectAnnotation(name='polygon', feature_schema_id=None, extra={}, value=Polygon(extra={}, points=[Point(extra={}, x=100.0, y=100.0), Point(extra={}, x=110.0, y=110.0), Point(extra={}, x=130.0, y=130.0), Point(extra={}, x=170.0, y=170.0), Point(extra={}, x=220.0, y=220.0), Point(extra={}, x=100.0, y=100.0)]), classifications=[]),\n", - " ObjectAnnotation(name='mask', feature_schema_id=None, extra={}, value=Mask(extra={}, mask=MaskData(im_bytes=None,file_path=None,url=https://storage.labelbox.com/cklgtitp0gi500732dgmg0p8l%2F4c5b600e-5b50-cf4a-df2b-28dbf1b1dddf-1?Expires=1646225060595&KeyName=labelbox-assets-key-3&Signature=aIZd6sj8UdiDUsPZBbTEtcNPWf4,arr=...), color=(0, 0, 0)), classifications=[]),\n", + "{'annotations': [ObjectAnnotation(name='point', feature_schema_id=None, extra={}, value=Point(extra={}, x=882.0, y=159.0), classifications=[]),\n", + " ObjectAnnotation(name='box', feature_schema_id=None, extra={}, value=Rectangle(extra={}, start=Point(extra={}, x=557.0, y=898.0), end=Point(extra={}, x=852.0, y=1140.0)), classifications=[]),\n", + " ObjectAnnotation(name='line', feature_schema_id=None, extra={}, value=Line(extra={}, points=[Point(extra={}, x=2534.353, y=249.471), Point(extra={}, x=2429.492, y=182.092), Point(extra={}, x=2294.322, y=221.962), Point(extra={}, x=2224.491, y=180.463), Point(extra={}, x=2136.123, y=204.716), Point(extra={}, x=1712.247, y=173.949), Point(extra={}, x=1703.838, y=84.438), Point(extra={}, x=1579.772, y=82.61), Point(extra={}, x=1583.442, y=167.552), Point(extra={}, x=1478.869, y=164.903), Point(extra={}, x=1418.941, y=318.149), Point(extra={}, x=1243.128, y=400.815), Point(extra={}, x=1022.067, y=319.007), Point(extra={}, x=892.367, y=379.216), Point(extra={}, x=670.273, y=364.408), Point(extra={}, x=613.114, y=288.16), Point(extra={}, x=377.559, y=238.251), Point(extra={}, x=368.087, y=185.064), Point(extra={}, x=246.557, y=167.286), Point(extra={}, x=236.648, y=285.61), Point(extra={}, x=90.929, y=326.412)]), classifications=[]),\n", + " ObjectAnnotation(name='polygon', feature_schema_id=None, extra={}, value=Polygon(extra={}, points=[Point(extra={}, x=1489.581, y=183.934), Point(extra={}, x=2278.306, y=256.885), Point(extra={}, x=2428.197, y=200.437), Point(extra={}, x=2560.0, y=335.419), Point(extra={}, x=2557.386, y=503.165), Point(extra={}, x=2320.596, y=503.103), Point(extra={}, x=2156.083, y=628.943), Point(extra={}, x=2161.111, y=785.519), Point(extra={}, x=2002.115, y=894.647), Point(extra={}, x=1838.456, y=877.874), Point(extra={}, x=1436.53, y=874.636), Point(extra={}, x=1411.403, y=758.579), Point(extra={}, x=1353.853, y=751.74), Point(extra={}, x=1345.264, y=453.461), Point(extra={}, x=1426.011, y=421.129), Point(extra={}, x=1489.581, y=183.934)]), classifications=[]),\n", + " ObjectAnnotation(name='mask', feature_schema_id=None, extra={}, value=Mask(extra={}, mask=MaskData(im_bytes=None,file_path=None,url=https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2F2ba259af-0914-adc4-7dce-d6ecf990ba12-1?Expires=1659035110433&KeyName=labelbox-assets-key-3&Signature=LVFadNLVlG1TzO0OuvSY7Qq72SM,arr=...), color=(0, 0, 0)), classifications=[]),\n", " ClassificationAnnotation(name='text', feature_schema_id=None, extra={}, value=Text(answer='the answer to the text question')),\n", " ClassificationAnnotation(name='checklist', feature_schema_id=None, extra={}, value=Checklist(name='checklist', answer=[ClassificationAnswer(name='first_checklist_answer', feature_schema_id=None, extra={}, keyframe=None), ClassificationAnswer(name='second_checklist_answer', feature_schema_id=None, extra={}, keyframe=None)])),\n", " ClassificationAnnotation(name='radio', feature_schema_id=None, extra={}, value=Radio(answer=ClassificationAnswer(name='second_radio_answer', feature_schema_id=None, extra={}, keyframe=None)))],\n", @@ -358,21 +464,17 @@ " 'uid': None}" ] }, - "execution_count": 11, "metadata": {}, - "output_type": "execute_result" + "execution_count": 35 } ], "source": [ - "image_data = ImageData(uid=data_row.uid)\n", - "\n", - "point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation = create_objects()\n", - "checklist_annotation, radio_annotation, text_annotation = create_classifications()\n", - "\n", + "# Create a Label object by identifying the applicavle data row in Labelbox and providing a list of annotations\n", "label = Label(\n", - " data=image_data,\n", + " data=ImageData(\n", + " uid=data_row.uid),\n", " annotations = [\n", - " point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation,\n", + " point_annotation, box_annotation, polyline_annotation, polygon_annotation, mask_annotation,\n", " text_annotation, checklist_annotation, radio_annotation\n", " ]\n", ")\n", @@ -382,7 +484,6 @@ " url = client.upload_data(content=obj_bytes, sign=True)\n", " return url\n", "\n", - "\n", "label.add_url_to_masks(signing_function)\n", "\n", "label.__dict__" @@ -417,70 +518,153 @@ }, { "cell_type": "code", - "execution_count": null, + "source": [ + "import copy # We import this python package so we can create copies of our hard-coded annotations and upload one copy to each" + ], + "metadata": { + "id": "0U_cA2Cw0pH1" + }, + "id": "0U_cA2Cw0pH1", + "execution_count": 16, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 39, "id": "53aaf87b-114f-4b56-a417-8c7cddc1f532", "metadata": { + "id": "53aaf87b-114f-4b56-a417-8c7cddc1f532", "colab": { "base_uri": "https://localhost:8080/" }, - "id": "53aaf87b-114f-4b56-a417-8c7cddc1f532", - "outputId": "43a3efd9-ee7e-4413-eee3-ef75f049ce96" + "outputId": "e525feac-9f8e-49e7-95d0-33932998b0bd" }, - "outputs": [], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "[{'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'point',\n", + " 'point': {'x': 882.0, 'y': 159.0},\n", + " 'uuid': 'adbdf3bf-6474-4beb-8726-3ee4bb3a35af'},\n", + " {'bbox': {'height': 242.0, 'left': 557.0, 'top': 898.0, 'width': 295.0},\n", + " 'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'box',\n", + " 'uuid': '29503cec-4a69-43d3-8ab1-64d6813d93d4'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'line': [{'x': 2534.353, 'y': 249.471},\n", + " {'x': 2429.492, 'y': 182.092},\n", + " {'x': 2294.322, 'y': 221.962},\n", + " {'x': 2224.491, 'y': 180.463},\n", + " {'x': 2136.123, 'y': 204.716},\n", + " {'x': 1712.247, 'y': 173.949},\n", + " {'x': 1703.838, 'y': 84.438},\n", + " {'x': 1579.772, 'y': 82.61},\n", + " {'x': 1583.442, 'y': 167.552},\n", + " {'x': 1478.869, 'y': 164.903},\n", + " {'x': 1418.941, 'y': 318.149},\n", + " {'x': 1243.128, 'y': 400.815},\n", + " {'x': 1022.067, 'y': 319.007},\n", + " {'x': 892.367, 'y': 379.216},\n", + " {'x': 670.273, 'y': 364.408},\n", + " {'x': 613.114, 'y': 288.16},\n", + " {'x': 377.559, 'y': 238.251},\n", + " {'x': 368.087, 'y': 185.064},\n", + " {'x': 246.557, 'y': 167.286},\n", + " {'x': 236.648, 'y': 285.61},\n", + " {'x': 90.929, 'y': 326.412}],\n", + " 'name': 'line',\n", + " 'uuid': 'c9221716-d76e-45ba-9983-cd09bded5909'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'polygon',\n", + " 'polygon': [{'x': 1489.581, 'y': 183.934},\n", + " {'x': 2278.306, 'y': 256.885},\n", + " {'x': 2428.197, 'y': 200.437},\n", + " {'x': 2560.0, 'y': 335.419},\n", + " {'x': 2557.386, 'y': 503.165},\n", + " {'x': 2320.596, 'y': 503.103},\n", + " {'x': 2156.083, 'y': 628.943},\n", + " {'x': 2161.111, 'y': 785.519},\n", + " {'x': 2002.115, 'y': 894.647},\n", + " {'x': 1838.456, 'y': 877.874},\n", + " {'x': 1436.53, 'y': 874.636},\n", + " {'x': 1411.403, 'y': 758.579},\n", + " {'x': 1353.853, 'y': 751.74},\n", + " {'x': 1345.264, 'y': 453.461},\n", + " {'x': 1426.011, 'y': 421.129},\n", + " {'x': 1489.581, 'y': 183.934}],\n", + " 'uuid': '66d74cc3-e163-4bd9-a4cd-499c5b33b1fa'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'mask': {'colorRGB': (0, 0, 0),\n", + " 'instanceURI': 'https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2F2ba259af-0914-adc4-7dce-d6ecf990ba12-1?Expires=1659035110433&KeyName=labelbox-assets-key-3&Signature=LVFadNLVlG1TzO0OuvSY7Qq72SM'},\n", + " 'name': 'mask',\n", + " 'uuid': 'b5ead711-9fdc-4fe8-b563-7cffdfbd1f14'},\n", + " {'answer': 'the answer to the text question',\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'text',\n", + " 'uuid': 'd31cdf47-055f-42d2-860c-8deefb25647f'},\n", + " {'answer': [{'name': 'first_checklist_answer'},\n", + " {'name': 'second_checklist_answer'}],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'checklist',\n", + " 'uuid': '9a851586-02fb-4894-ab72-f1967b00a6f9'},\n", + " {'answer': {'name': 'second_radio_answer'},\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'radio',\n", + " 'uuid': '7e92e01b-740d-48b4-935e-560ba0b63fa5'}]" + ] + }, + "metadata": {}, + "execution_count": 39 + } + ], "source": [ - "mal_label = Label(\n", - " data=image_data,\n", - " annotations = [\n", - " point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation,\n", - " text_annotation, checklist_annotation, radio_annotation\n", - " ]\n", - ")\n", - "\n", - "label.add_url_to_masks(signing_function)\n", - "\n", - "ndjson_labels = list(NDJsonConverter.serialize([mal_label]))\n", + "# Make a copy of the label to upload to the MAL project\n", + "mal_label = copy.deepcopy(label)\n", "\n", - "ndjson_labels" + "# Convert our label from a Labelbox class object to the underlying NDJSON format required for upload - uploads can be directly built in this syntax as well\n", + "mal_ndjson = list(NDJsonConverter.serialize([mal_label]))\n", + "mal_ndjson" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 18, "id": "c66672c7-33e8-4d5d-b79d-2ac76d830341", "metadata": { "id": "c66672c7-33e8-4d5d-b79d-2ac76d830341" }, "outputs": [], "source": [ + "# Upload our label using Model-Assisted Labeling\n", "upload_job = MALPredictionImport.create_from_objects(\n", " client = client, \n", " project_id = mal_project.uid, \n", - " name=\"upload_label_import_job\", \n", - " predictions=ndjson_labels)" + " name=\"mal_job\", \n", + " predictions=mal_ndjson)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "id": "2a8f9e5f-eeeb-4cfa-9b97-a09495a64d41", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "2a8f9e5f-eeeb-4cfa-9b97-a09495a64d41", - "outputId": "6b2c938f-04eb-408a-c78e-a3258f765f4e" + "outputId": "83237748-ede9-49fe-f0c2-5e046173ef17" }, "outputs": [ { - "name": "stderr", "output_type": "stream", - "text": [ - "INFO:labelbox.schema.annotation_import:Sleeping for 10 seconds...\n" - ] - }, - { "name": "stdout", - "output_type": "stream", "text": [ "Errors: []\n" ] @@ -515,80 +699,150 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "id": "e8d4e99b-ad7e-48b9-8073-afb764d7c5b4", "metadata": { + "id": "e8d4e99b-ad7e-48b9-8073-afb764d7c5b4", "colab": { "base_uri": "https://localhost:8080/" }, - "id": "e8d4e99b-ad7e-48b9-8073-afb764d7c5b4", - "outputId": "384aea4d-9352-4192-c395-e39a44d5b6a4" + "outputId": "704fac54-8f45-46f0-ce2d-3769c5b11f23" }, - "outputs": [], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "[{'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'point',\n", + " 'point': {'x': 882.0, 'y': 159.0},\n", + " 'uuid': '078ba35d-733e-403f-9299-519685ef2998'},\n", + " {'bbox': {'height': 242.0, 'left': 557.0, 'top': 898.0, 'width': 295.0},\n", + " 'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'box',\n", + " 'uuid': '1a4e8c0e-98e5-4adc-9723-552067e09d1c'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'line': [{'x': 2534.353, 'y': 249.471},\n", + " {'x': 2429.492, 'y': 182.092},\n", + " {'x': 2294.322, 'y': 221.962},\n", + " {'x': 2224.491, 'y': 180.463},\n", + " {'x': 2136.123, 'y': 204.716},\n", + " {'x': 1712.247, 'y': 173.949},\n", + " {'x': 1703.838, 'y': 84.438},\n", + " {'x': 1579.772, 'y': 82.61},\n", + " {'x': 1583.442, 'y': 167.552},\n", + " {'x': 1478.869, 'y': 164.903},\n", + " {'x': 1418.941, 'y': 318.149},\n", + " {'x': 1243.128, 'y': 400.815},\n", + " {'x': 1022.067, 'y': 319.007},\n", + " {'x': 892.367, 'y': 379.216},\n", + " {'x': 670.273, 'y': 364.408},\n", + " {'x': 613.114, 'y': 288.16},\n", + " {'x': 377.559, 'y': 238.251},\n", + " {'x': 368.087, 'y': 185.064},\n", + " {'x': 246.557, 'y': 167.286},\n", + " {'x': 236.648, 'y': 285.61},\n", + " {'x': 90.929, 'y': 326.412}],\n", + " 'name': 'line',\n", + " 'uuid': '4250dc8a-4d71-4b8a-a6c8-dc1197745afa'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'polygon',\n", + " 'polygon': [{'x': 1489.581, 'y': 183.934},\n", + " {'x': 2278.306, 'y': 256.885},\n", + " {'x': 2428.197, 'y': 200.437},\n", + " {'x': 2560.0, 'y': 335.419},\n", + " {'x': 2557.386, 'y': 503.165},\n", + " {'x': 2320.596, 'y': 503.103},\n", + " {'x': 2156.083, 'y': 628.943},\n", + " {'x': 2161.111, 'y': 785.519},\n", + " {'x': 2002.115, 'y': 894.647},\n", + " {'x': 1838.456, 'y': 877.874},\n", + " {'x': 1436.53, 'y': 874.636},\n", + " {'x': 1411.403, 'y': 758.579},\n", + " {'x': 1353.853, 'y': 751.74},\n", + " {'x': 1345.264, 'y': 453.461},\n", + " {'x': 1426.011, 'y': 421.129},\n", + " {'x': 1489.581, 'y': 183.934}],\n", + " 'uuid': '997c1234-bda1-4226-9b1c-30fc468eb747'},\n", + " {'classifications': [],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'mask': {'colorRGB': (0, 0, 0),\n", + " 'instanceURI': 'https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2F2ba259af-0914-adc4-7dce-d6ecf990ba12-1?Expires=1659035110433&KeyName=labelbox-assets-key-3&Signature=LVFadNLVlG1TzO0OuvSY7Qq72SM'},\n", + " 'name': 'mask',\n", + " 'uuid': '92ff52c8-7621-455f-b28f-a97fd06224b3'},\n", + " {'answer': 'the answer to the text question',\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'text',\n", + " 'uuid': '5d98f605-cf02-499f-9376-263f76ee7439'},\n", + " {'answer': [{'name': 'first_checklist_answer'},\n", + " {'name': 'second_checklist_answer'}],\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'checklist',\n", + " 'uuid': '74e4c460-f980-47a2-97eb-29cb2df107d4'},\n", + " {'answer': {'name': 'second_radio_answer'},\n", + " 'dataRow': {'id': 'cl63z7sm83xv608vs0bpjb51e'},\n", + " 'name': 'radio',\n", + " 'uuid': 'f413b3a2-1e71-473c-b3b0-c952791284df'}]" + ] + }, + "metadata": {}, + "execution_count": 36 + } + ], "source": [ - "#for the purpose of this notebook, we will need to reset the schema ids of our checklist and radio answers\n", - "image_data = ImageData(uid=data_row.uid)\n", - "\n", - "point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation = create_objects()\n", - "checklist_annotation, radio_annotation, text_annotation = create_classifications()\n", + "# Make a copy of the label to upload to the Label Import project\n", + "li_label = copy.deepcopy(label)\n", "\n", - "li_label = Label(\n", - " data=image_data,\n", - " annotations = [\n", - " point_annotation, rectangle_annotation, line_annotation, polygon_annotation, mask_annotation,\n", - " text_annotation, checklist_annotation, radio_annotation\n", - " ]\n", - ")\n", - "\n", - "ndjson_labels = list(NDJsonConverter.serialize([li_label]))\n", - "\n", - "ndjson_labels" + "# Convert our label from a Labelbox class object to the underlying NDJSON format required for upload - uploads can be directly built in this syntax as well\n", + "li_ndjson = list(NDJsonConverter.serialize([li_label]))\n", + "li_ndjson" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 37, "id": "e937ea0a-8beb-4dbc-974b-0316f0b980a5", "metadata": { "id": "e937ea0a-8beb-4dbc-974b-0316f0b980a5" }, "outputs": [], "source": [ + "# Upload our label using Label Import\n", "upload_job = LabelImport.create_from_objects(\n", " client = client, \n", " project_id = li_project.uid, \n", - " name=\"upload_label_import_job\", \n", - " labels=ndjson_labels)" + " name=\"label_import_job\", \n", + " labels=li_ndjson)" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 38, "id": "3669b646-2d41-4c98-9e5b-f8ef3ce82f35", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "3669b646-2d41-4c98-9e5b-f8ef3ce82f35", - "outputId": "b70ec739-ac16-45c3-e407-442e34838b8e" + "outputId": "2545fd27-813f-41e3-bee3-7bb600c71c3a" }, "outputs": [ { - "name": "stderr", "output_type": "stream", - "text": [ - "INFO:labelbox.schema.annotation_import:Sleeping for 10 seconds...\n" - ] - }, - { "name": "stdout", - "output_type": "stream", "text": [ "Errors: []\n" ] } ], "source": [ + "# Errors will appear for each annotation that failed.\n", + "# Empty list means that there were no errors\n", + "# This will provide information only after the upload_job is complete, so we do not need to worry about having to rerun\n", "print(\"Errors:\", upload_job.errors)" ] } @@ -596,7 +850,7 @@ "metadata": { "colab": { "collapsed_sections": [], - "name": "image_mal.ipynb", + "name": "image_annotation_import.ipynb", "provenance": [] }, "kernelspec": {