├── EDA ├── EDA_all_image ├── EDA_new_batch.ipynb └── EDA_single_image.ipynb ├── LICENSE ├── PID_Detection_detectron2.ipynb ├── PID_symbol_classification.ipynb ├── README.md └── utils ├── Border_removal.ipynb ├── Data_creation.ipynb └── SU_to_COCO.ipynb /EDA/EDA_new_batch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "EDA_new_batch.ipynb", 7 | "provenance": [], 8 | "authorship_tag": "ABX9TyNVG12A8KvQInQt8JBarEof", 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | }, 15 | "language_info": { 16 | "name": "python" 17 | } 18 | }, 19 | "cells": [ 20 | { 21 | "cell_type": "markdown", 22 | "metadata": { 23 | "id": "view-in-github", 24 | "colab_type": "text" 25 | }, 26 | "source": [ 27 | "\"Open" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "metadata": { 33 | "id": "ni4IYKeSNaiA" 34 | }, 35 | "source": [ 36 | "from google.colab import drive\n", 37 | "drive.mount('/content/drive')" 38 | ], 39 | "execution_count": null, 40 | "outputs": [] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": { 45 | "id": "u7eN22Lw9OAd" 46 | }, 47 | "source": [ 48 | "# Import Library " 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "metadata": { 54 | "id": "7dO-0qklzopo" 55 | }, 56 | "source": [ 57 | "import json\n", 58 | "import pandas as pd\n", 59 | "import cv2\n", 60 | "import random\n", 61 | "import os\n", 62 | "from os import listdir\n", 63 | "from os.path import isfile, join" 64 | ], 65 | "execution_count": null, 66 | "outputs": [] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": { 71 | "id": "z08aK5XD9VFy" 72 | }, 73 | "source": [ 74 | "# New annotations" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "metadata": { 80 | "id": "V9jWdhZnNqAY" 81 | }, 82 | "source": [ 83 | "annotation_dir = \"/content/drive/MyDrive/Official Folder DigitalTwins/Data/coco_converted/annots\"\n", 84 | "img_anno = [join(annotation_dir, f) for f in listdir(annotation_dir) if isfile(join(annotation_dir, f))]" 85 | ], 86 | "execution_count": null, 87 | "outputs": [] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "metadata": { 92 | "id": "w_DO-PxlPPzt" 93 | }, 94 | "source": [ 95 | "final_anno = []\n", 96 | "for file in img_anno:\n", 97 | " with open(file) as f:\n", 98 | " anno = json.load(f)\n", 99 | " final_anno.extend(anno['annotations'])" 100 | ], 101 | "execution_count": null, 102 | "outputs": [] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "metadata": { 107 | "id": "3cA8hIFhRRMf" 108 | }, 109 | "source": [ 110 | "df = pd.DataFrame(final_anno)" 111 | ], 112 | "execution_count": null, 113 | "outputs": [] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "metadata": { 118 | "colab": { 119 | "base_uri": "https://localhost:8080/" 120 | }, 121 | "id": "ntakIs2LRV7t", 122 | "outputId": "df6a259d-7202-4b00-9e66-5a9145297297" 123 | }, 124 | "source": [ 125 | "df.info()" 126 | ], 127 | "execution_count": null, 128 | "outputs": [ 129 | { 130 | "output_type": "stream", 131 | "text": [ 132 | "\n", 133 | "RangeIndex: 6373 entries, 0 to 6372\n", 134 | "Data columns (total 10 columns):\n", 135 | " # Column Non-Null Count Dtype \n", 136 | "--- ------ -------------- ----- \n", 137 | " 0 area 4316 non-null float64\n", 138 | " 1 bbox 6373 non-null object \n", 139 | " 2 category_id 6373 non-null int64 \n", 140 | " 3 annot_id 6373 non-null int64 \n", 141 | " 4 image_id 6373 non-null int64 \n", 142 | " 5 iscrowd 6373 non-null int64 \n", 143 | " 6 segmentation 4316 non-null object \n", 144 | " 7 classId 6373 non-null object \n", 145 | " 8 className 6373 non-null object \n", 146 | " 9 value 6373 non-null object \n", 147 | "dtypes: float64(1), int64(4), object(5)\n", 148 | "memory usage: 498.0+ KB\n" 149 | ], 150 | "name": "stdout" 151 | } 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "metadata": { 157 | "colab": { 158 | "base_uri": "https://localhost:8080/", 159 | "height": 289 160 | }, 161 | "id": "UYHpy_4zRYxc", 162 | "outputId": "6505b73a-9b30-4b66-8535-81154c2bc2ad" 163 | }, 164 | "source": [ 165 | "df.head()" 166 | ], 167 | "execution_count": null, 168 | "outputs": [ 169 | { 170 | "output_type": "execute_result", 171 | "data": { 172 | "text/html": [ 173 | "
\n", 174 | "\n", 187 | "\n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | "
areabboxcategory_idannot_idimage_idiscrowdsegmentationclassIdclassNamevalue
024226.470188[2065.2572, 4933.39, 156.34539999999998, 154.9...0000[2065.2572, 4933.39, 2221.6026, 4933.39, 2221....303a720dInstrument
125591.603699[3375.9372, 4858.5614000000005, 161.0264, 158....0100[3375.9372, 4858.5614000000005, 3536.9636, 485...ce708ed0Instrument
233076.899801[1715.1184, 4926.1058, 192.8572, 171.509799999...0200[1715.1184, 4926.1058, 1907.9756, 4926.1058, 1...88588391text41LAL 14
315912.918696[4805.5145999999995, 4279.1364, 129.1955999999...0300[4805.5145999999995, 4279.1364, 4934.710199999...af6b0c8fUnidentified
47769.853904[3721.395, 3626.2072, 141.3662, 54.9626]0400[3721.395, 3626.2072, 3862.7612, 3626.2072, 38...d6952e31Valve
\n", 271 | "
" 272 | ], 273 | "text/plain": [ 274 | " area ... value\n", 275 | "0 24226.470188 ... \n", 276 | "1 25591.603699 ... \n", 277 | "2 33076.899801 ... 41LAL 14\n", 278 | "3 15912.918696 ... \n", 279 | "4 7769.853904 ... \n", 280 | "\n", 281 | "[5 rows x 10 columns]" 282 | ] 283 | }, 284 | "metadata": {}, 285 | "execution_count": 93 286 | } 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "metadata": { 292 | "colab": { 293 | "base_uri": "https://localhost:8080/" 294 | }, 295 | "id": "ru55qFnHRYtx", 296 | "outputId": "7e56b12c-271c-4d79-ff37-5fd54497a120" 297 | }, 298 | "source": [ 299 | "df.className.unique().shape" 300 | ], 301 | "execution_count": null, 302 | "outputs": [ 303 | { 304 | "output_type": "execute_result", 305 | "data": { 306 | "text/plain": [ 307 | "(18,)" 308 | ] 309 | }, 310 | "metadata": {}, 311 | "execution_count": 26 312 | } 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "metadata": { 318 | "id": "GssTTnT2No4I" 319 | }, 320 | "source": [ 321 | "line = df[df.className == 'line']" 322 | ], 323 | "execution_count": null, 324 | "outputs": [] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "metadata": { 329 | "colab": { 330 | "base_uri": "https://localhost:8080/", 331 | "height": 204 332 | }, 333 | "id": "Z-sItXfINvO6", 334 | "outputId": "18fdeedf-5d92-447c-e05c-cc8fd7738852" 335 | }, 336 | "source": [ 337 | "line.head()" 338 | ], 339 | "execution_count": null, 340 | "outputs": [ 341 | { 342 | "output_type": "execute_result", 343 | "data": { 344 | "text/html": [ 345 | "
\n", 346 | "\n", 359 | "\n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | "
areabboxcategory_idannot_idimage_idiscrowdsegmentationclassIdclassNamevalue
98NaN[4722.1928, 4301.651199999999, 87.0666, 62.2468]29800None2eb6393dline
99NaN[4722.1928, 4301.651199999999, 87.0666, 62.2468]29900None5416f233line
100NaN[4722.1928, 4301.651199999999, 87.0666, 62.2468]210000None6372b6b0line
101NaN[4722.1928, 4301.651199999999, 87.0666, 62.2468]210100None0862930cline
102NaN[4722.1928, 4301.651199999999, 87.0666, 62.2468]210200None32ce779bline
\n", 443 | "
" 444 | ], 445 | "text/plain": [ 446 | " area bbox ... className value\n", 447 | "98 NaN [4722.1928, 4301.651199999999, 87.0666, 62.2468] ... line \n", 448 | "99 NaN [4722.1928, 4301.651199999999, 87.0666, 62.2468] ... line \n", 449 | "100 NaN [4722.1928, 4301.651199999999, 87.0666, 62.2468] ... line \n", 450 | "101 NaN [4722.1928, 4301.651199999999, 87.0666, 62.2468] ... line \n", 451 | "102 NaN [4722.1928, 4301.651199999999, 87.0666, 62.2468] ... line \n", 452 | "\n", 453 | "[5 rows x 10 columns]" 454 | ] 455 | }, 456 | "metadata": {}, 457 | "execution_count": 101 458 | } 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "metadata": { 464 | "colab": { 465 | "base_uri": "https://localhost:8080/" 466 | }, 467 | "id": "NBL0ZYIURYqT", 468 | "outputId": "56e59025-a420-4763-81bd-3dcf70d2dd90" 469 | }, 470 | "source": [ 471 | "df.className.unique()" 472 | ], 473 | "execution_count": null, 474 | "outputs": [ 475 | { 476 | "output_type": "execute_result", 477 | "data": { 478 | "text/plain": [ 479 | "array(['Instrument', 'text', 'Unidentified', 'Valve', 'Flow_Direction',\n", 480 | " 'Plug', 'Flange', 'Tank_Vessel', 'unidentified', 'line', 'Pump',\n", 481 | " 'Engine', 'Line_Break', 'Actuator', 'Connector', 'Concentric',\n", 482 | " 'Separator', 'Flange_Blind'], dtype=object)" 483 | ] 484 | }, 485 | "metadata": {}, 486 | "execution_count": 94 487 | } 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "metadata": { 493 | "id": "BTzfVUrXNUXm" 494 | }, 495 | "source": [ 496 | "df.className = df.className.str.lower()" 497 | ], 498 | "execution_count": null, 499 | "outputs": [] 500 | }, 501 | { 502 | "cell_type": "code", 503 | "metadata": { 504 | "colab": { 505 | "base_uri": "https://localhost:8080/" 506 | }, 507 | "id": "5MpAwrcLNYYg", 508 | "outputId": "a2f7caa1-808c-45a2-8581-21b3c93920e1" 509 | }, 510 | "source": [ 511 | "df.className.unique(), df.className.unique().shape" 512 | ], 513 | "execution_count": null, 514 | "outputs": [ 515 | { 516 | "output_type": "execute_result", 517 | "data": { 518 | "text/plain": [ 519 | "(array(['instrument', 'text', 'unidentified', 'valve', 'flow_direction',\n", 520 | " 'plug', 'flange', 'tank_vessel', 'line', 'pump', 'engine',\n", 521 | " 'line_break', 'actuator', 'connector', 'concentric', 'separator',\n", 522 | " 'flange_blind'], dtype=object), (17,))" 523 | ] 524 | }, 525 | "metadata": {}, 526 | "execution_count": 99 527 | } 528 | ] 529 | }, 530 | { 531 | "cell_type": "markdown", 532 | "metadata": { 533 | "id": "8etrNLf1Sv9W" 534 | }, 535 | "source": [ 536 | "# Old Annotations" 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "metadata": { 542 | "id": "YKEoNa-kRYfh" 543 | }, 544 | "source": [ 545 | "with open(\"/content/PID (1).json\") as f:\n", 546 | " ann = json.load(f)" 547 | ], 548 | "execution_count": null, 549 | "outputs": [] 550 | }, 551 | { 552 | "cell_type": "code", 553 | "metadata": { 554 | "colab": { 555 | "base_uri": "https://localhost:8080/" 556 | }, 557 | "id": "M16OckLCUgrW", 558 | "outputId": "cf9a6b9d-20e6-458d-abdb-841f5ffd3b85" 559 | }, 560 | "source": [ 561 | "ann.keys()" 562 | ], 563 | "execution_count": null, 564 | "outputs": [ 565 | { 566 | "output_type": "execute_result", 567 | "data": { 568 | "text/plain": [ 569 | "dict_keys(['info', 'licenses', 'images', 'annotations', 'categories'])" 570 | ] 571 | }, 572 | "metadata": {}, 573 | "execution_count": 103 574 | } 575 | ] 576 | }, 577 | { 578 | "cell_type": "code", 579 | "metadata": { 580 | "id": "XetWwU-BWeB9" 581 | }, 582 | "source": [ 583 | "" 584 | ], 585 | "execution_count": null, 586 | "outputs": [] 587 | }, 588 | { 589 | "cell_type": "code", 590 | "metadata": { 591 | "id": "cvUaVjxmVq3B" 592 | }, 593 | "source": [ 594 | "old_df = pd.DataFrame(ann['annotations'])" 595 | ], 596 | "execution_count": null, 597 | "outputs": [] 598 | }, 599 | { 600 | "cell_type": "code", 601 | "metadata": { 602 | "id": "yBBiikTESwMd", 603 | "colab": { 604 | "base_uri": "https://localhost:8080/" 605 | }, 606 | "outputId": "c7e7d4d4-c8c5-4311-95cd-11ef29f2684a" 607 | }, 608 | "source": [ 609 | "old_df.info()" 610 | ], 611 | "execution_count": null, 612 | "outputs": [ 613 | { 614 | "output_type": "stream", 615 | "text": [ 616 | "\n", 617 | "RangeIndex: 6225 entries, 0 to 6224\n", 618 | "Data columns (total 7 columns):\n", 619 | " # Column Non-Null Count Dtype \n", 620 | "--- ------ -------------- ----- \n", 621 | " 0 id 6225 non-null int64 \n", 622 | " 1 image_id 6225 non-null int64 \n", 623 | " 2 segmentation 6225 non-null object\n", 624 | " 3 iscrowd 6225 non-null int64 \n", 625 | " 4 bbox 6225 non-null object\n", 626 | " 5 area 6225 non-null int64 \n", 627 | " 6 category_id 6225 non-null int64 \n", 628 | "dtypes: int64(5), object(2)\n", 629 | "memory usage: 340.6+ KB\n" 630 | ], 631 | "name": "stdout" 632 | } 633 | ] 634 | }, 635 | { 636 | "cell_type": "code", 637 | "metadata": { 638 | "colab": { 639 | "base_uri": "https://localhost:8080/" 640 | }, 641 | "id": "VoxIhle4WILU", 642 | "outputId": "46457e2a-6ca4-4887-d152-518dd43db74a" 643 | }, 644 | "source": [ 645 | "6373+6225" 646 | ], 647 | "execution_count": null, 648 | "outputs": [ 649 | { 650 | "output_type": "execute_result", 651 | "data": { 652 | "text/plain": [ 653 | "12598" 654 | ] 655 | }, 656 | "metadata": {}, 657 | "execution_count": 106 658 | } 659 | ] 660 | }, 661 | { 662 | "cell_type": "code", 663 | "metadata": { 664 | "id": "seRN5DgnXE-r" 665 | }, 666 | "source": [ 667 | "def add_class(col):\n", 668 | " for i in ann['categories']:\n", 669 | " if i['id'] == col:\n", 670 | " return i['name'].lower()" 671 | ], 672 | "execution_count": null, 673 | "outputs": [] 674 | }, 675 | { 676 | "cell_type": "code", 677 | "metadata": { 678 | "id": "xPwcCCmPXolA" 679 | }, 680 | "source": [ 681 | "old_df['className'] = old_df['category_id'].apply(add_class)" 682 | ], 683 | "execution_count": null, 684 | "outputs": [] 685 | }, 686 | { 687 | "cell_type": "code", 688 | "metadata": { 689 | "colab": { 690 | "base_uri": "https://localhost:8080/", 691 | "height": 204 692 | }, 693 | "id": "QKSHjAmKWNla", 694 | "outputId": "f0a8525d-86b3-476e-ac01-4be00f8c9667" 695 | }, 696 | "source": [ 697 | "old_df.head()" 698 | ], 699 | "execution_count": null, 700 | "outputs": [ 701 | { 702 | "output_type": "execute_result", 703 | "data": { 704 | "text/html": [ 705 | "
\n", 706 | "\n", 719 | "\n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | "
idimage_idsegmentationiscrowdbboxareacategory_idclassName
011[[5130.92, 3420.16, 5130.92, 3529.81, 5241.13,...0[5130.92, 3420.16, 110.21000000000004, 109.650...385600352833instrument
121[[3520.11, 3419.77, 3520.11, 3529.25, 3630.55,...0[3520.11, 3419.77, 110.44000000000005, 109.480...386350352833instrument
231[[2655.96, 3419.43, 2655.96, 3529.17, 2764.54,...0[2655.96, 3419.43, 108.57999999999993, 109.740...379777352833instrument
341[[3640.81, 3074.69, 3640.81, 3118.19, 3682.77,...0[3640.81, 3074.69, 41.960000000000036, 43.5]127764352842concentric
451[[3466.15, 3282.72, 3466.15, 3341.81, 3522.46,...0[3466.15, 3282.72, 56.309999999999945, 59.0900...184894352845line_break
\n", 791 | "
" 792 | ], 793 | "text/plain": [ 794 | " id image_id ... category_id className\n", 795 | "0 1 1 ... 352833 instrument\n", 796 | "1 2 1 ... 352833 instrument\n", 797 | "2 3 1 ... 352833 instrument\n", 798 | "3 4 1 ... 352842 concentric\n", 799 | "4 5 1 ... 352845 line_break\n", 800 | "\n", 801 | "[5 rows x 8 columns]" 802 | ] 803 | }, 804 | "metadata": {}, 805 | "execution_count": 115 806 | } 807 | ] 808 | }, 809 | { 810 | "cell_type": "code", 811 | "metadata": { 812 | "colab": { 813 | "base_uri": "https://localhost:8080/" 814 | }, 815 | "id": "bpQXEuzMWUNA", 816 | "outputId": "e435ba67-7531-471f-e4ff-a37f45805982" 817 | }, 818 | "source": [ 819 | "print((old_df.className.unique())), print(df.className.unique())" 820 | ], 821 | "execution_count": null, 822 | "outputs": [ 823 | { 824 | "output_type": "stream", 825 | "text": [ 826 | "['instrument' 'concentric' 'line_break' 'flow_direction' 'unidentified'\n", 827 | " 'inside text' 'text' 'tank_vessel' 'valve' 'flange' 'actuator'\n", 828 | " 'connector' 'separator' 'engine' 'plug' 'flange_blind' 'piping_lines'\n", 829 | " 'other_lines']\n", 830 | "['instrument' 'text' 'unidentified' 'valve' 'flow_direction' 'plug'\n", 831 | " 'flange' 'tank_vessel' 'line' 'pump' 'engine' 'line_break' 'actuator'\n", 832 | " 'connector' 'concentric' 'separator' 'flange_blind']\n" 833 | ], 834 | "name": "stdout" 835 | }, 836 | { 837 | "output_type": "execute_result", 838 | "data": { 839 | "text/plain": [ 840 | "(None, None)" 841 | ] 842 | }, 843 | "metadata": {}, 844 | "execution_count": 116 845 | } 846 | ] 847 | }, 848 | { 849 | "cell_type": "code", 850 | "metadata": { 851 | "id": "JLYyi1kuX_EH" 852 | }, 853 | "source": [ 854 | "old = old_df.className.unique().tolist()\n", 855 | "old.sort()\n", 856 | "new = df.className.unique().tolist()\n", 857 | "new.sort()" 858 | ], 859 | "execution_count": null, 860 | "outputs": [] 861 | }, 862 | { 863 | "cell_type": "code", 864 | "metadata": { 865 | "colab": { 866 | "base_uri": "https://localhost:8080/" 867 | }, 868 | "id": "Fs0OnHhtYpzy", 869 | "outputId": "b912c53b-c1f8-4a22-a4ed-e63c23d2cadc" 870 | }, 871 | "source": [ 872 | "old, len(old)" 873 | ], 874 | "execution_count": null, 875 | "outputs": [ 876 | { 877 | "output_type": "execute_result", 878 | "data": { 879 | "text/plain": [ 880 | "(['actuator',\n", 881 | " 'concentric',\n", 882 | " 'connector',\n", 883 | " 'engine',\n", 884 | " 'flange',\n", 885 | " 'flange_blind',\n", 886 | " 'flow_direction',\n", 887 | " 'inside text',\n", 888 | " 'instrument',\n", 889 | " 'line_break',\n", 890 | " 'other_lines',\n", 891 | " 'piping_lines',\n", 892 | " 'plug',\n", 893 | " 'separator',\n", 894 | " 'tank_vessel',\n", 895 | " 'text',\n", 896 | " 'unidentified',\n", 897 | " 'valve'],\n", 898 | " 18)" 899 | ] 900 | }, 901 | "metadata": {}, 902 | "execution_count": 129 903 | } 904 | ] 905 | }, 906 | { 907 | "cell_type": "code", 908 | "metadata": { 909 | "id": "3EYITe-BPCRG" 910 | }, 911 | "source": [ 912 | "Total number of classes in old annotations are 18,\n", 913 | "These are the classes that old have but not there in new one -> \"inside text\", \"other_lines\", and \"piping_lines\".\n", 914 | "Total number of classes in New annotations are 17,\n", 915 | "Classes that are present in new annotations but are not in old one -> \"line\" and \"pump\"\n", 916 | "\n", 917 | "My suggestion is to combine \"other_lines\" and \"piping_lines\" to create one \"line\" class similar to New annotation. \n", 918 | "And also combine \"inside text\" class with \"text\" class in old annotation. \n", 919 | "After that we can use both annotations combined. " 920 | ], 921 | "execution_count": null, 922 | "outputs": [] 923 | }, 924 | { 925 | "cell_type": "code", 926 | "metadata": { 927 | "colab": { 928 | "base_uri": "https://localhost:8080/" 929 | }, 930 | "id": "-60U6U65Oxox", 931 | "outputId": "07f51bec-da5a-44c3-c029-f6f3b84be8dc" 932 | }, 933 | "source": [ 934 | "new, len(new)" 935 | ], 936 | "execution_count": null, 937 | "outputs": [ 938 | { 939 | "output_type": "execute_result", 940 | "data": { 941 | "text/plain": [ 942 | "(['actuator',\n", 943 | " 'concentric',\n", 944 | " 'connector',\n", 945 | " 'engine',\n", 946 | " 'flange',\n", 947 | " 'flange_blind',\n", 948 | " 'flow_direction',\n", 949 | " 'instrument',\n", 950 | " 'line',\n", 951 | " 'line_break',\n", 952 | " 'plug',\n", 953 | " 'pump',\n", 954 | " 'separator',\n", 955 | " 'tank_vessel',\n", 956 | " 'text',\n", 957 | " 'unidentified',\n", 958 | " 'valve'],\n", 959 | " 17)" 960 | ] 961 | }, 962 | "metadata": {}, 963 | "execution_count": 130 964 | } 965 | ] 966 | }, 967 | { 968 | "cell_type": "code", 969 | "metadata": { 970 | "id": "HWjAnPahY4xk" 971 | }, 972 | "source": [ 973 | "class_comp = {\n", 974 | " \"old\": old,\n", 975 | " \"new\": new\n", 976 | "}" 977 | ], 978 | "execution_count": null, 979 | "outputs": [] 980 | }, 981 | { 982 | "cell_type": "code", 983 | "metadata": { 984 | "id": "2pwur4_nY6MR" 985 | }, 986 | "source": [ 987 | "" 988 | ], 989 | "execution_count": null, 990 | "outputs": [] 991 | }, 992 | { 993 | "cell_type": "code", 994 | "metadata": { 995 | "id": "Gnc7ewVAOlHp" 996 | }, 997 | "source": [ 998 | "" 999 | ], 1000 | "execution_count": null, 1001 | "outputs": [] 1002 | } 1003 | ] 1004 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # P&ID Detection 2 | *** 3 | This project was done under Omdena organisation with problem set to [digitized the Energy Industry](https://omdena.com/projects/energy-transformation/). 4 | *** 5 | **The Project Goals** 6 | --------------------- 7 | 8 |        1. Detection and localization of different symbols present in a P&ID.   9 | 10 |           List of symbols which majorly fall in these categories: 11 | 12 |               -- Line symbols 13 | 14 |               -- Valve symbols 15 | 16 |               -- Piping symbols (tees, flanges, reducers, etc) 17 | 18 |               -- Pumps symbols 19 | 20 |               -- Vessels symbols 21 | 22 |               -- Tanks symbols 23 | 24 |               -- Instrumentation symbols 25 | 26 |     2. Use of OCR for detection of Tag numbers and then associating them with their respective symbols. 27 | 28 |     3. Detection of lines that correspond to Pipes and Cables. Mapping them with their LineID number. 29 | -------------------------------------------------------------------------------- /utils/Data_creation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Data_creation.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "authorship_tag": "ABX9TyOF+dTgFVc/QhT835/b7LOR", 10 | "include_colab_link": true 11 | }, 12 | "kernelspec": { 13 | "name": "python3", 14 | "display_name": "Python 3" 15 | }, 16 | "language_info": { 17 | "name": "python" 18 | } 19 | }, 20 | "cells": [ 21 | { 22 | "cell_type": "markdown", 23 | "metadata": { 24 | "id": "view-in-github", 25 | "colab_type": "text" 26 | }, 27 | "source": [ 28 | "\"Open" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": { 34 | "id": "1njm0tzFx3gn" 35 | }, 36 | "source": [ 37 | "# This notebook is used to create dataset for classification.\n", 38 | "`Only bbox were used and polylines were skipped`" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "metadata": { 44 | "colab": { 45 | "base_uri": "https://localhost:8080/" 46 | }, 47 | "id": "aW32o8DpIzMG", 48 | "outputId": "75d19a10-157e-4dfa-984b-d14412a80a5a" 49 | }, 50 | "source": [ 51 | "from google.colab import drive\n", 52 | "drive.mount('/content/drive')" 53 | ], 54 | "execution_count": null, 55 | "outputs": [ 56 | { 57 | "output_type": "stream", 58 | "text": [ 59 | "Mounted at /content/drive\n" 60 | ], 61 | "name": "stdout" 62 | } 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "metadata": { 68 | "id": "x3cwyCviKOR5", 69 | "colab": { 70 | "base_uri": "https://localhost:8080/" 71 | }, 72 | "outputId": "9d8a0f9b-79a4-48f7-dad0-1de696f54802" 73 | }, 74 | "source": [ 75 | "!unzip \"/content/drive/MyDrive/Official Folder DigitalTwins/Data/Annotated/Image_annotation_8images_batch1.zip\"" 76 | ], 77 | "execution_count": null, 78 | "outputs": [ 79 | { 80 | "output_type": "stream", 81 | "text": [ 82 | "Archive: /content/drive/MyDrive/Official Folder DigitalTwins/Data/Annotated/Image_annotation_8images_batch1.zip\n", 83 | " creating: Image_annotation_8images_batch1/\n", 84 | " creating: Image_annotation_8images_batch1/classes/\n", 85 | " inflating: Image_annotation_8images_batch1/classes/classes.json \n", 86 | " inflating: Image_annotation_8images_batch1/2001_3.png___objects.json \n", 87 | " inflating: Image_annotation_8images_batch1/1414.png___objects.json \n", 88 | " inflating: Image_annotation_8images_batch1/1420.png___objects.json \n", 89 | " inflating: Image_annotation_8images_batch1/2001_2.png___objects.json \n", 90 | " inflating: Image_annotation_8images_batch1/2201_1.png___objects.json \n", 91 | " inflating: Image_annotation_8images_batch1/2001_1.png___objects.json \n", 92 | " inflating: Image_annotation_8images_batch1/1422.png___objects.json \n", 93 | " inflating: Image_annotation_8images_batch1/1421.png___objects.json \n" 94 | ], 95 | "name": "stdout" 96 | } 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "metadata": { 102 | "id": "u0zojmsxKoJ9", 103 | "colab": { 104 | "base_uri": "https://localhost:8080/" 105 | }, 106 | "outputId": "1b089f72-5236-4efd-82c2-7e1b2f08fdb1" 107 | }, 108 | "source": [ 109 | "!unzip -d imgs \"/content/drive/MyDrive/Official Folder DigitalTwins/Data/Not-Annotated/PIDs-images_200dpi.zip\" " 110 | ], 111 | "execution_count": null, 112 | "outputs": [ 113 | { 114 | "output_type": "stream", 115 | "text": [ 116 | "Archive: /content/drive/MyDrive/Official Folder DigitalTwins/Data/Not-Annotated/PIDs-images_200dpi.zip\n", 117 | " inflating: imgs/1414.png \n", 118 | " inflating: imgs/1420.png \n", 119 | " inflating: imgs/1421.png \n", 120 | " inflating: imgs/1422.png \n", 121 | " inflating: imgs/2001_1.png \n", 122 | " inflating: imgs/2001_2.png \n", 123 | " inflating: imgs/2001_3.png \n", 124 | " inflating: imgs/2101.png \n", 125 | " inflating: imgs/2201_1.png \n", 126 | " inflating: imgs/2201_2.png \n" 127 | ], 128 | "name": "stdout" 129 | } 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "metadata": { 135 | "id": "D9HKE6u4KsF1" 136 | }, 137 | "source": [ 138 | "import json\n", 139 | "import pandas as pd\n", 140 | "import cv2\n", 141 | "import random\n", 142 | "import os\n", 143 | "from os import listdir\n", 144 | "from os.path import isfile, join\n", 145 | "import numpy as np\n", 146 | "import matplotlib.pyplot as plt\n", 147 | "import matplotlib.image as mpimg\n", 148 | "from torch.utils.data.sampler import SubsetRandomSampler\n", 149 | "from torch.autograd import Variable\n", 150 | "from torch.utils.data import random_split\n", 151 | "from torchvision.datasets import ImageFolder\n", 152 | "from skimage import io, transform\n", 153 | "from PIL import Image\n", 154 | "import torchvision as vision\n", 155 | "from torchvision import transforms, datasets" 156 | ], 157 | "execution_count": null, 158 | "outputs": [] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "metadata": { 163 | "id": "54VWA_bmL6uX" 164 | }, 165 | "source": [ 166 | "with open(\"/content/Image_annotation_8images_batch1/1414.png___objects.json\") as f:\n", 167 | " anno = json.load(f)" 168 | ], 169 | "execution_count": null, 170 | "outputs": [] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "metadata": { 175 | "id": "UShPurNtDKbt" 176 | }, 177 | "source": [ 178 | "pip install superannotate" 179 | ], 180 | "execution_count": null, 181 | "outputs": [] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "metadata": { 186 | "id": "9lA-ID2PDJNa" 187 | }, 188 | "source": [ 189 | "import superannotate as sa\n", 190 | "sa.export_annotation(\"/content/Image_annotation_8images_batch1\", \"/content/new\", \"COCO\", \"PID\", project_type='Vector', task='object_detection')" 191 | ], 192 | "execution_count": null, 193 | "outputs": [] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "metadata": { 198 | "id": "tQKmk9k6DV3-" 199 | }, 200 | "source": [ 201 | "with open(\"/content/new/PID.json\") as f:\n", 202 | " pid = json.load(f)" 203 | ], 204 | "execution_count": null, 205 | "outputs": [] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "metadata": { 210 | "colab": { 211 | "base_uri": "https://localhost:8080/" 212 | }, 213 | "id": "jXERj-c5F84s", 214 | "outputId": "9d9483e5-512c-494f-9e09-d63d43b518b0" 215 | }, 216 | "source": [ 217 | "pid.keys()" 218 | ], 219 | "execution_count": null, 220 | "outputs": [ 221 | { 222 | "output_type": "execute_result", 223 | "data": { 224 | "text/plain": [ 225 | "dict_keys(['info', 'licenses', 'images', 'annotations', 'categories'])" 226 | ] 227 | }, 228 | "metadata": { 229 | "tags": [] 230 | }, 231 | "execution_count": 8 232 | } 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "metadata": { 238 | "colab": { 239 | "base_uri": "https://localhost:8080/" 240 | }, 241 | "id": "ILXByvi0GASO", 242 | "outputId": "4fab25c0-25f7-4640-fac9-2e8f959a4813" 243 | }, 244 | "source": [ 245 | "len(pid['annotations'])" 246 | ], 247 | "execution_count": null, 248 | "outputs": [ 249 | { 250 | "output_type": "execute_result", 251 | "data": { 252 | "text/plain": [ 253 | "6225" 254 | ] 255 | }, 256 | "metadata": { 257 | "tags": [] 258 | }, 259 | "execution_count": 12 260 | } 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "metadata": { 266 | "id": "G6cGVq2vF0W8" 267 | }, 268 | "source": [ 269 | "pp = pd.DataFrame(pid)" 270 | ], 271 | "execution_count": null, 272 | "outputs": [] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "metadata": { 277 | "colab": { 278 | "base_uri": "https://localhost:8080/" 279 | }, 280 | "id": "-2toNG9sZv4p", 281 | "outputId": "8ba1ff19-d8bf-42e1-bd79-0b41e86a8b15" 282 | }, 283 | "source": [ 284 | "anno.keys()" 285 | ], 286 | "execution_count": null, 287 | "outputs": [ 288 | { 289 | "output_type": "execute_result", 290 | "data": { 291 | "text/plain": [ 292 | "dict_keys(['metadata', 'comments', 'tags', 'instances'])" 293 | ] 294 | }, 295 | "metadata": { 296 | "tags": [] 297 | }, 298 | "execution_count": 6 299 | } 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "metadata": { 305 | "id": "TY5QtHY1MFYV" 306 | }, 307 | "source": [ 308 | "# Creating DataFrame of Instances\n", 309 | "# All data associated to give image is under Instance key.\n", 310 | "df = pd.DataFrame(anno['instances'])" 311 | ], 312 | "execution_count": null, 313 | "outputs": [] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "metadata": { 318 | "colab": { 319 | "base_uri": "https://localhost:8080/" 320 | }, 321 | "id": "pVZuoGNFMFVl", 322 | "outputId": "06ecb809-070a-44c1-f7de-fcb1d0a2520c" 323 | }, 324 | "source": [ 325 | "df.className.unique()" 326 | ], 327 | "execution_count": null, 328 | "outputs": [ 329 | { 330 | "output_type": "execute_result", 331 | "data": { 332 | "text/plain": [ 333 | "array(['Instrument', 'tank_vessel', 'engine', 'valve', 'flange', 'plug',\n", 334 | " 'flange_blind', 'Concentric', 'Actuator', 'connector',\n", 335 | " 'line_break', 'flow_direction', 'piping_lines', 'other_lines',\n", 336 | " 'Unidentified', 'Inside text', 'text'], dtype=object)" 337 | ] 338 | }, 339 | "metadata": { 340 | "tags": [] 341 | }, 342 | "execution_count": 25 343 | } 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "metadata": { 349 | "id": "3IfYbxk5cORO" 350 | }, 351 | "source": [ 352 | "# Here only taking bbox and removing polylines\n", 353 | "ddf = df[df.type == 'bbox']" 354 | ], 355 | "execution_count": null, 356 | "outputs": [] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "metadata": { 361 | "colab": { 362 | "base_uri": "https://localhost:8080/" 363 | }, 364 | "id": "SkUSkjuVcPs4", 365 | "outputId": "ed5101e5-0186-4350-8029-89bebd49dd29" 366 | }, 367 | "source": [ 368 | "# piping_lines and other_lines are removed as they were polylines\n", 369 | "ddf.className.unique()" 370 | ], 371 | "execution_count": null, 372 | "outputs": [ 373 | { 374 | "output_type": "execute_result", 375 | "data": { 376 | "text/plain": [ 377 | "array(['Instrument', 'tank_vessel', 'engine', 'valve', 'flange', 'plug',\n", 378 | " 'flange_blind', 'Concentric', 'Actuator', 'connector',\n", 379 | " 'line_break', 'flow_direction', 'Unidentified', 'Inside text',\n", 380 | " 'text'], dtype=object)" 381 | ] 382 | }, 383 | "metadata": { 384 | "tags": [] 385 | }, 386 | "execution_count": 27 387 | } 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "metadata": { 393 | "id": "otooEQVZ879Y" 394 | }, 395 | "source": [ 396 | "# Just copied from above cell\n", 397 | "class_name_list = ['Instrument', 'tank_vessel', 'engine', 'separator', 'valve',\n", 398 | " 'flange', 'plug', 'flange_blind', 'Concentric', 'Actuator',\n", 399 | " 'connector', 'line_break', 'flow_direction', \n", 400 | " 'Unidentified', 'Inside text', 'text']" 401 | ], 402 | "execution_count": null, 403 | "outputs": [] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "metadata": { 408 | "id": "6SajooNOMFTL" 409 | }, 410 | "source": [ 411 | "'''\n", 412 | " The code below is used to create class folders based on the above class name list.\n", 413 | "'''\n", 414 | "\n", 415 | "main_dir = \"/content/drive/MyDrive/cropped_img/\"\n", 416 | "for dir in class_name_list:\n", 417 | " if not os.path.exists(main_dir):\n", 418 | " os.makedirs(main_dir)\n", 419 | " if not os.path.exists(main_dir+dir):\n", 420 | " os.makedirs(main_dir+dir)" 421 | ], 422 | "execution_count": null, 423 | "outputs": [] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "metadata": { 428 | "id": "mZD95bWfK0gM" 429 | }, 430 | "source": [ 431 | "def create_dataset(img, img_name, df):\n", 432 | " \"\"\" Function to create_dataset\n", 433 | " Params:\n", 434 | " img: image (use cv2.imread(img_path))\n", 435 | " img_name: name of the image, used to create new name for cropped images \n", 436 | " df: dataframe which contain all information (Created using annotation file)\n", 437 | " \"\"\"\n", 438 | " \n", 439 | " # Main directory name \n", 440 | " main_dir = \"/content/drive/MyDrive/cropped_img\"\n", 441 | "\n", 442 | " for i in range(0, len(df['points'])):\n", 443 | " if df.type[i] != \"polyline\": # Skipping the polylines\n", 444 | " try :\n", 445 | " new_image_path = main_dir + \"/\" +str(df['className'][i])+ \"/\" + str(df['className'][i]) + \"_{}_{}.jpg\".format(img_name, i+1)\n", 446 | " if not os.path.exists(new_image_path):\n", 447 | " bbox = df.points[i]\n", 448 | " x1, x2, y1, y2 = int(bbox['x1']), int(bbox['x2']), int(bbox['y1']), int(bbox['y2'])\n", 449 | " crop_img = img[y1:y2, x1:x2] \n", 450 | " print(df['className'][i], \"--> \", new_image_path, crop_img.shape)\n", 451 | " cv2.imwrite(new_image_path, crop_img)\n", 452 | " except:\n", 453 | " pass" 454 | ], 455 | "execution_count": null, 456 | "outputs": [] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "metadata": { 461 | "id": "h5FQkYGp7hc4" 462 | }, 463 | "source": [ 464 | "# Getting all image annotation file path \n", 465 | "annotation_dir = \"/content/Image_annotation_8images_batch1/\"\n", 466 | "img_anno = [(annotation_dir+f) for f in listdir(annotation_dir) if isfile(join(annotation_dir, f))]" 467 | ], 468 | "execution_count": null, 469 | "outputs": [] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "metadata": { 474 | "id": "TZt-TtfL7p_B" 475 | }, 476 | "source": [ 477 | "# Path of the image dir\n", 478 | "img_dir = \"/content/imgs/\"\n", 479 | "\n", 480 | "# Looping over annotation file\n", 481 | "for i in img_anno:\n", 482 | " with open(i) as f:\n", 483 | " anno = json.load(f)\n", 484 | " img_name = anno['metadata']['name']\n", 485 | " #Reading image\n", 486 | " img = cv2.imread(img_dir + img_name)\n", 487 | " \n", 488 | " # Creating DataFrame of instances list\n", 489 | " df = pd.DataFrame(anno['instances'])\n", 490 | "\n", 491 | " create_dataset(img, img_name.split(\".\")[0], df)" 492 | ], 493 | "execution_count": null, 494 | "outputs": [] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "metadata": { 499 | "colab": { 500 | "base_uri": "https://localhost:8080/" 501 | }, 502 | "id": "JLFT8KN0bA-0", 503 | "outputId": "e5f89c99-5ffb-43a9-a552-cdb5a48f81de" 504 | }, 505 | "source": [ 506 | "ig = cv2.imread(\"/content/drive/MyDrive/cropped_img/Actuator/Actuator_251.jpg\")\n", 507 | "ig.shape" 508 | ], 509 | "execution_count": null, 510 | "outputs": [ 511 | { 512 | "output_type": "execute_result", 513 | "data": { 514 | "text/plain": [ 515 | "(58, 59, 3)" 516 | ] 517 | }, 518 | "metadata": { 519 | "tags": [] 520 | }, 521 | "execution_count": 219 522 | } 523 | ] 524 | }, 525 | { 526 | "cell_type": "markdown", 527 | "metadata": { 528 | "id": "rMj62Jygwvmf" 529 | }, 530 | "source": [ 531 | "# Simple Dataloader for Classification part (WIP)" 532 | ] 533 | }, 534 | { 535 | "cell_type": "code", 536 | "metadata": { 537 | "id": "NL0pdSqUUVXK" 538 | }, 539 | "source": [ 540 | "def prepare_dataset(dataset_path):\n", 541 | " \"\"\" Function to create train and validation loader.\n", 542 | " Params:\n", 543 | " dataset_path: path where all images are.\n", 544 | " \n", 545 | " returns: \n", 546 | " train_loader: train loader with batch size of 64\n", 547 | " validation_loader: validation loader with batch size of 64\n", 548 | " \n", 549 | " Note: Split ratio and batch sizes are pre-defined you can change it in this function.\n", 550 | " \"\"\"\n", 551 | "\n", 552 | " labels = os.listdir(dataset_path)\n", 553 | "\n", 554 | " # Here images are resized and converted to grayscale so that we have data consistency for other tasks\n", 555 | " dataset = ImageFolder(\n", 556 | " dataset_path,\n", 557 | " transforms.Compose([transforms.Resize((32,32)),\n", 558 | " transforms.ToTensor(),transforms.Grayscale(num_output_channels=1)])\n", 559 | " )\n", 560 | " \n", 561 | " # Validation split 15%\n", 562 | " val_split = int(len(dataset)*0.15)\n", 563 | " train_split = len(dataset) - val_split\n", 564 | "\n", 565 | " train_dataset, val_dataset = random_split(dataset, [train_split, val_split])\n", 566 | "\n", 567 | " # to make sure the split is right.\n", 568 | " assert (len(train_dataset)+len(val_dataset)) == len(dataset)\n", 569 | "\n", 570 | " train_loader = torch.utils.data.DataLoader(train_dataset, 64, shuffle=True)\n", 571 | " validation_loader = torch.utils.data.DataLoader(val_dataset, 128) \n", 572 | "\n", 573 | " return (train_loader, validation_loader)" 574 | ], 575 | "execution_count": null, 576 | "outputs": [] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "metadata": { 581 | "id": "PQW2V0ZrbP9z" 582 | }, 583 | "source": [ 584 | "dataset_dir = \"/content/drive/MyDrive/cropped_img\"\n", 585 | "train_loader, validation_loader = prepare_dataset(dataset_dir)" 586 | ], 587 | "execution_count": null, 588 | "outputs": [] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "metadata": { 593 | "colab": { 594 | "base_uri": "https://localhost:8080/", 595 | "height": 551 596 | }, 597 | "id": "7OdsiC304jdC", 598 | "outputId": "3cec3e01-6c4b-4cf2-edad-2a33d04a48df" 599 | }, 600 | "source": [ 601 | "examples = enumerate(train_loader)\n", 602 | "batch_idx, (example_data, example_targets) = next(examples)\n", 603 | "import matplotlib.pyplot as plt\n", 604 | "\n", 605 | "fig = plt.figure()\n", 606 | "for i in range(6):\n", 607 | " plt.subplot(2,3,i+1)\n", 608 | " plt.tight_layout()\n", 609 | " plt.imshow(example_data[i][0], cmap='gray', interpolation='none')\n", 610 | " plt.title(\"Ground Truth: {}\".format(example_targets[i]))\n", 611 | " plt.xticks([])\n", 612 | " plt.yticks([])\n", 613 | "fig" 614 | ], 615 | "execution_count": null, 616 | "outputs": [ 617 | { 618 | "output_type": "execute_result", 619 | "data": { 620 | "image/png": "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\n", 621 | "text/plain": [ 622 | "
" 623 | ] 624 | }, 625 | "metadata": { 626 | "tags": [] 627 | }, 628 | "execution_count": 308 629 | }, 630 | { 631 | "output_type": "display_data", 632 | "data": { 633 | "image/png": "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\n", 634 | "text/plain": [ 635 | "
" 636 | ] 637 | }, 638 | "metadata": { 639 | "tags": [] 640 | } 641 | } 642 | ] 643 | }, 644 | { 645 | "cell_type": "code", 646 | "metadata": { 647 | "id": "W25-E58a-uUA" 648 | }, 649 | "source": [ 650 | "" 651 | ], 652 | "execution_count": null, 653 | "outputs": [] 654 | } 655 | ] 656 | } -------------------------------------------------------------------------------- /utils/SU_to_COCO.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "SU_to_COCO.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "authorship_tag": "ABX9TyOmPnIv2gG+2pggEPebGeit", 10 | "include_colab_link": true 11 | }, 12 | "kernelspec": { 13 | "name": "python3", 14 | "display_name": "Python 3" 15 | }, 16 | "language_info": { 17 | "name": "python" 18 | } 19 | }, 20 | "cells": [ 21 | { 22 | "cell_type": "markdown", 23 | "metadata": { 24 | "id": "view-in-github", 25 | "colab_type": "text" 26 | }, 27 | "source": [ 28 | "\"Open" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "metadata": { 34 | "id": "Pa86bRrUI_KT" 35 | }, 36 | "source": [ 37 | "from google.colab import drive\n", 38 | "drive.mount('/content/drive')" 39 | ], 40 | "execution_count": null, 41 | "outputs": [] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "metadata": { 46 | "id": "mu_4sfLcJEvf" 47 | }, 48 | "source": [ 49 | "" 50 | ], 51 | "execution_count": null, 52 | "outputs": [] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "metadata": { 57 | "id": "cp0idyxeJEs1" 58 | }, 59 | "source": [ 60 | "import json\n", 61 | "import pandas as pd\n", 62 | "import cv2\n", 63 | "import random\n", 64 | "import os\n", 65 | "from os import listdir\n", 66 | "from os.path import isfile, join" 67 | ], 68 | "execution_count": null, 69 | "outputs": [] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "metadata": { 74 | "id": "4MBIk9F5JEqE" 75 | }, 76 | "source": [ 77 | "" 78 | ], 79 | "execution_count": null, 80 | "outputs": [] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": { 85 | "id": "f_fSuYR-JlzX" 86 | }, 87 | "source": [ 88 | "## Custom SU to COCO conversion" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "metadata": { 94 | "id": "D5Z_MXFpJEnR" 95 | }, 96 | "source": [ 97 | "# Getting all image annotation file path \n", 98 | "annotation_dir = \"/content/drive/MyDrive/Official Folder DigitalTwins/Data/Batch-1/Image_annotation_8images_batch1\"\n", 99 | "img_anno = [join(annotation_dir,f) for f in listdir(annotation_dir) if isfile(join(annotation_dir, f))]" 100 | ], 101 | "execution_count": null, 102 | "outputs": [] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "metadata": { 107 | "id": "If5BMbeRJEkW" 108 | }, 109 | "source": [ 110 | "" 111 | ], 112 | "execution_count": null, 113 | "outputs": [] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "metadata": { 118 | "id": "WbFNpfShJEhc" 119 | }, 120 | "source": [ 121 | "def new_format(json_path, id):\n", 122 | " ann = {\n", 123 | " \"info\": \"Batch2\",\n", 124 | " \"categories\": [\n", 125 | " {\n", 126 | " \"supercategory\": \"Symbol\",\n", 127 | " \"id\": 0,\n", 128 | " \"name\": \"Symbol\"\n", 129 | " },\n", 130 | " {\n", 131 | " \"supercategory\": \"Text\",\n", 132 | " \"id\": 1,\n", 133 | " \"name\": \"Text\"\n", 134 | " },\n", 135 | " {\n", 136 | " \"supercategory\": \"Line\",\n", 137 | " \"id\": 2,\n", 138 | " \"name\": \"Line\"\n", 139 | " }\n", 140 | " ],\n", 141 | " \"image\": {\n", 142 | " \"image_id\": None,\n", 143 | " \"file_name\": None,\n", 144 | " \"height\": None,\n", 145 | " \"width\": None\n", 146 | " },\n", 147 | " \"annotations\": []\n", 148 | " }\n", 149 | " image_name = json_path.split(\"/\")[-1].split(\".\")[0]\n", 150 | " new_name = \"coco_annots_{}.json\".format(image_name)\n", 151 | " with open(json_path) as file:\n", 152 | " an = json.load(file)\n", 153 | " ann['image']['image_id'] = id\n", 154 | " ann['image']['file_name'] = an['metadata']['name']\n", 155 | " ann['image']['height'] = an['metadata']['height']\n", 156 | " ann['image']['width'] = an['metadata']['width']\n", 157 | "\n", 158 | " \n", 159 | " for an_id, j in enumerate(an['instances']):\n", 160 | " if j[\"className\"] == \"piping_lines\" or j[\"className\"] == \"other_lines\":\n", 161 | " pass\n", 162 | " else:\n", 163 | " # print(j['points']['x1'])\n", 164 | " new = {\n", 165 | " \"area\": ann['image']['height']*ann['image']['width'],\n", 166 | " \"bbox\": None,\n", 167 | " \"category_id\": 0,\n", 168 | " \"annot_id\": an_id,\n", 169 | " \"image_id\": id,\n", 170 | " \"iscrowd\": 0,\n", 171 | " \"segmentation\": None,\n", 172 | " \"classId\": j['classId'],\n", 173 | " \"className\": j['className'].lower(),\n", 174 | " \"value\": \" \"\n", 175 | " }\n", 176 | "\n", 177 | " # if len(j['points'])> 4:\n", 178 | " # print(j['className'])\n", 179 | " # print(j['type'])\n", 180 | " # print(j['points'])\n", 181 | "\n", 182 | " if j['type'] == 'bbox':\n", 183 | " new['bbox'] = [j['points']['x1'], j['points']['x2'], j['points']['y1'], j['points']['y2']]\n", 184 | " # else:\n", 185 | " # new['bbox'] = j['points']\n", 186 | " \n", 187 | "\n", 188 | " if j['className'].lower() == \"inside text\" or j['className'] == \"text\":\n", 189 | " new[\"className\"] = \"text\"\n", 190 | " try:\n", 191 | " new['value'] = j['pointLabels']['0']\n", 192 | " except:\n", 193 | " new['value'] = \" \"\n", 194 | " ann['annotations'].append(new)\n", 195 | " # print(ann)\n", 196 | " new_folder = join(annotationsroot_dir, new_name)\n", 197 | " with open(new_folder, 'w') as outfile:\n", 198 | " json.dump(ann, outfile)\n", 199 | " " 200 | ], 201 | "execution_count": null, 202 | "outputs": [] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "metadata": { 207 | "id": "OioN1xIwJEea" 208 | }, 209 | "source": [ 210 | "for id, path in enumerate(img_anno):\n", 211 | " print(id, path)\n", 212 | " new_format(path, id)" 213 | ], 214 | "execution_count": null, 215 | "outputs": [] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "metadata": { 220 | "id": "tXtMhjlLJEbY" 221 | }, 222 | "source": [ 223 | "" 224 | ], 225 | "execution_count": null, 226 | "outputs": [] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": { 231 | "id": "IoIb173qJeK7" 232 | }, 233 | "source": [ 234 | "## SU to COCO using Superannotate API" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "metadata": { 240 | "id": "HMAc_TIpJEYt" 241 | }, 242 | "source": [ 243 | "import superannotate as sa\n", 244 | "sa.export_annotation(\"Annotation folder\", \"Output folder\", \"COCO\", \"Final folder name\", project_type='Vector', task='object_detection')" 245 | ], 246 | "execution_count": null, 247 | "outputs": [] 248 | } 249 | ] 250 | } --------------------------------------------------------------------------------