1/* 2Author: Pedro F. Proença 3 - On page load, a new unlabeled image is requested. Require at least two urls 4 - After image submit, annotation data is posted to the server as a json 5*/ 6 7// These variables should be returned by the server 8var image_id; 9var image_url; // = "https://live.staticflickr.com/65535/47066877034_dd3535e6ea_b.jpg"; 10var image_url_o; // = "https://live.staticflickr.com/65535/47066877034_6fdbc4c882_o.jpg"; 11var multiple_images_available; 12var nr_annotations_reviewed_so_far = 0; 13var mobile_device = false; 14 15var object_cats = new Array(); 16var object_ctxs = new Array(); 17var perimeters = new Array(); 18var perimeter_per_object = new Array(); 19var perimeter = new Array(); 20var hr_enabled = false; 21var button_background = false; 22var canvas = document.getElementById("jPolygon"); 23var ctx; 24var hue = ~~(Math.random() * 360); 25var object_color = "hsla(" + hue + ", 100%, 60%, 1.0)"; 26var object_color_transparent = "hsla(" + hue + ", 100%, 60%, 0.5)"; 27var object_colors = new Array(); 28var object_colors_transparent = new Array(); 29var image_original_height; 30var image_original_width; 31var cat_sorted_by_id = {}; 32var object_id_selected; 33 34// Min distance between cursor and anchor point to select it 35var min_dist_2_anchor = 100; 36 37// Add key listener 38document.addEventListener('keydown', function(event) { 39 var key = event.which || event.keyCode; 40 if (key ==72){ 41 change_resolution(); 42 } 43 if (key == 13){ 44 submit_step_1(); 45 } 46}, false); 47 48// load_image() requests, fills image urls & dims 49function load_image(){ 50 51 $('#spinner').show(); 52 ctx = canvas.getContext("2d"); 53 ctx.clearRect(0, 0, canvas.width, canvas.height); 54 55 $.ajax({ 56 type: 'POST', 57 url: 'http://178.128.33.132:5901/twirp/v1.taco.annotations.Service/Unprocessed', 58 contentType: "application/json", 59 dataType: 'json', 60 data: '{}' 61 }).success( function(data) { 62 image_url = data['flick_640_url']; 63 image_url_o = data['flick_url']; 64 image_id = data['id']; 65 66 if (image_url == ' '){ 67 multiple_images_available = false; 68 }else{ 69 multiple_images_available = true; 70 } 71 72 73 // Get original image size 74 var img = new Image(); 75 img.src = image_url_o; 76 77 img.onload = function(){ 78 $('#spinner').hide(); 79 image_original_width = this.width; 80 image_original_height = this.height; 81 }; 82 83 clear_canvas(); 84 85 }); 86 87 // Use this while we work on the endpoint above 88 // $.getJSON("jsondata/unlabeled.json", function(data) { 89 // image_url = data.url; 90 // image_url_o = data.url_o; 91 // image_id = data.id; 92 // 93 // var img = new Image(); 94 // img.src = image_url_o; 95 // 96 // // Get image meta 97 // img.onload = function(){ 98 // image_original_width = this.width; 99 // image_original_height = this.height; 100 // }; 101 // 102 // clear_canvas(); 103 // }); 104 105} 106 107async function load_image_mobile(){ 108 mobile_device = true 109 load_image(); 110 await sleep(1000); 111 alert('This tool is currently experimental for mobile devices. We recommend using a computer for better user experience and results, but if you wish to continue with this device follow our tips.') 112 await sleep(1000); 113 hr_enabled = true; 114 clear_canvas(); 115 116} 117 118function sleep(ms) { 119 return new Promise(resolve => setTimeout(resolve, ms)); 120} 121 122function line_intersects(p0, p1, p2, p3) { 123 var s1_x, s1_y, s2_x, s2_y; 124 s1_x = p1['x'] - p0['x']; 125 s1_y = p1['y'] - p0['y']; 126 s2_x = p3['x'] - p2['x']; 127 s2_y = p3['y'] - p2['y']; 128 129 var s, t; 130 s = (-s1_y * (p0['x'] - p2['x']) + s1_x * (p0['y'] - p2['y'])) / (-s2_x * s1_y + s1_x * s2_y); 131 t = ( s2_x * (p0['y'] - p2['y']) - s2_y * (p0['x'] - p2['x'])) / (-s2_x * s1_y + s1_x * s2_y); 132 133 if (s >= 0 && s <= 1 && t >= 0 && t <= 1) 134 { 135 // Collision detected 136 return true; 137 } 138 return false; // No collision 139} 140 141function point(x, y, color){ 142 ctx.fillStyle= color; 143 ctx.strokeStyle = color; 144 ctx.fillRect(x-3,y-3,6,6); 145 ctx.fill 146 ctx.moveTo(x,y); 147} 148 149function undo(){ 150 ctx = undefined; 151 perimeter.pop(); 152 start(true); 153} 154 155 156function change_resolution(){ 157 button_background = document.getElementById('skip_btn').style; 158 if (hr_enabled) { 159 document.getElementById('hr_button').style = button_background; 160 } else { 161 document.getElementById('hr_button').style.backgroundColor = "rgb(188,190,191)"; 162 } 163 hr_enabled = !hr_enabled; 164 165 // Actual restart image 166 start(true); 167} 168 169function scale_polygons(scale_x, scale_y){ 170 171 for(var j=0; j<perimeters.length; j++){ 172 perimeter_j = perimeters[j] 173 for(var i=0; i<perimeter_j.length; i++){ 174 perimeter_j[i]['x'] = perimeter_j[i]['x']*scale_x; 175 perimeter_j[i]['y'] = perimeter_j[i]['y']*scale_y; 176 } 177 } 178 for(var i=0; i<perimeter.length; i++){ 179 perimeter[i]['x'] = perimeter[i]['x']*scale_x; 180 perimeter[i]['y'] = perimeter[i]['y']*scale_y; 181 } 182} 183 184function redraw(){ 185 186 ctx.lineWidth = 2; 187 188 for(var j=0; j<perimeters.length; j++){ 189 perimeter_old = perimeters[j] 190 ctx.strokeStyle = object_colors[j]; 191 ctx.lineCap = "round"; 192 ctx.beginPath(); 193 for(var i=0; i<perimeter_old.length; i++){ 194 if(i==0){ 195 ctx.moveTo(perimeter_old[i]['x'],perimeter_old[i]['y']); 196 } else { 197 ctx.lineTo(perimeter_old[i]['x'],perimeter_old[i]['y']); 198 } 199 } 200 ctx.lineTo(perimeter_old[0]['x'],perimeter_old[0]['y']); 201 ctx.closePath(); 202 ctx.fillStyle = object_colors_transparent[j] 203 ctx.fill(); 204 ctx.stroke(); 205 206 // Redraw anchor points 207 for(var i=0; i<perimeter_old.length; i++){ 208 ctx.moveTo(perimeter_old[i]['x'],perimeter_old[i]['y']); 209 point(perimeter_old[i]['x'],perimeter_old[i]['y'],object_colors[j]); 210 } 211 ctx.stroke(); 212 } 213} 214 215// This gets called on page loading 216function clear_canvas(){ 217 218 ctx = undefined; 219 perimeter = new Array(); 220 perimeters = new Array(); 221 perimeter_per_object = new Array(); 222 object_cats = new Array(); 223 object_ctxs = new Array(); 224 object_colors = new Array(); 225 object_colors_transparent = new Array(); 226 227 perimeter_per_object.push(0); 228 229 fill_class_list(); 230 231 $('#object_btn_list').empty(); 232 233 start(); 234} 235 236function draw(full,end){ 237 ctx.lineWidth = 2; 238 //ctx.strokeStyle = "white"; 239 ctx.lineCap = "round"; 240 ctx.beginPath(); 241 242 // Draw only last line 243 if(!full){ 244 nr_pts = perimeter.length; 245 if(nr_pts==1){ 246 ctx.moveTo(perimeter[0]['x'],perimeter[0]['y']); 247 end || point(perimeter[0]['x'],perimeter[0]['y'],object_color); 248 }else{ 249 point(perimeter[nr_pts-2]['x'],perimeter[nr_pts-2]['y'],object_color); 250 ctx.lineTo(perimeter[nr_pts-1]['x'],perimeter[nr_pts-1]['y']); 251 end || point(perimeter[nr_pts-1]['x'],perimeter[nr_pts-1]['y'],object_color); 252 } 253 }else{ 254 // Draw all segment 255 for(var i=0; i<perimeter.length; i++){ 256 if(i==0){ 257 ctx.moveTo(perimeter[i]['x'],perimeter[i]['y']); 258 end || point(perimeter[i]['x'],perimeter[i]['y'],object_color); 259 } else { 260 ctx.lineTo(perimeter[i]['x'],perimeter[i]['y']); 261 end || point(perimeter[i]['x'],perimeter[i]['y'],object_color); 262 } 263 } 264 if(end){ 265 ctx.lineTo(perimeter[0]['x'],perimeter[0]['y']); 266 ctx.closePath(); 267 ctx.fillStyle = object_color_transparent 268 ctx.fill(); 269 ctx.strokeStyle = object_color 270 } 271 } 272 ctx.stroke(); 273 // print coordinates 274 // if(perimeter.length == 0){ 275 // document.getElementById('coordinates').value = ''; 276 // } else { 277 // document.getElementById('coordinates').value = JSON.stringify(perimeter); 278 // } 279} 280 281function check_intersect(x,y){ 282 if(perimeter.length < 4){ 283 return false;
284 } 285 var p0 = new Array(); 286 var p1 = new Array(); 287 var p2 = new Array(); 288 var p3 = new Array(); 289 290 p2['x'] = perimeter[perimeter.length-1]['x']; 291 p2['y'] = perimeter[perimeter.length-1]['y']; 292 p3['x'] = x; 293 p3['y'] = y; 294 295 for(var i=0; i<perimeter.length-1; i++){ 296 p0['x'] = perimeter[i]['x']; 297 p0['y'] = perimeter[i]['y']; 298 p1['x'] = perimeter[i+1]['x']; 299 p1['y'] = perimeter[i+1]['y']; 300 if(p1['x'] == p2['x'] && p1['y'] == p2['y']){ continue; } 301 if(p0['x'] == p3['x'] && p0['y'] == p3['y']){ continue; } 302 if(line_intersects(p0,p1,p2,p3)==true){ 303 return true; 304 } 305 } 306 return false; 307} 308 309function hover(event) { 310 rect = canvas.getBoundingClientRect(); 311 x = event.clientX - rect.left; 312 y = event.clientY - rect.top; 313 314 if (perimeter.length>0){ 315 sqr_dist_2_origin = Math.pow(x - perimeter[0]['x'],2) + Math.pow(y - perimeter[0]['y'],2); 316 sqr_dist_2_last_point = Math.pow(x - perimeter[perimeter.length-1]['x'],2) + Math.pow(y - perimeter[perimeter.length-1]['y'],2); 317 318 if (sqr_dist_2_origin<min_dist_2_anchor || sqr_dist_2_last_point<min_dist_2_anchor){ 319 canvas.style.cursor="default"; 320 }else{ 321 canvas.style.cursor="crosshair"; 322 } 323 }else{ 324 canvas.style.cursor="crosshair"; 325 } 326 return 327} 328 329function point_it(event) { 330 331 //TODO: canvas.style.cursor="default"; 332 333 var rect, x, y; 334 335 if(event.ctrlKey || event.which === 3 || event.button === 2){ 336 if(perimeter.length==2){ 337 alert('You need at least three points'); 338 return false; 339 } 340 341 close_polygon(); 342 343 event.preventDefault(); 344 return false; 345 } else { 346 rect = canvas.getBoundingClientRect(); 347 x = event.clientX - rect.left; 348 y = event.clientY - rect.top; 349 350 if (perimeter.length>0){ 351 352 sqr_dist_2_last_point = Math.pow(x - perimeter[perimeter.length-1]['x'],2) + Math.pow(y - perimeter[perimeter.length-1]['y'],2); 353 354 if (sqr_dist_2_last_point < min_dist_2_anchor){ 355 undo() 356 return false; 357 } 358 359 if (perimeter.length>1000){ 360 alert('You have inserted too many points!'); 361 return false; 362 } 363 364 sqr_dist_2_origin = Math.pow(x - perimeter[0]['x'],2) + Math.pow(y - perimeter[0]['y'],2); 365 366 if (sqr_dist_2_origin < min_dist_2_anchor){ 367 close_polygon(); 368 event.preventDefault(); 369 // Ask user if we are done w/ this object 370 $("#modal_1").modal(); 371 return false; 372 } 373 if(check_intersect(x,y)){ 374 alert('The line you are drawing intersect another line'); 375 return false; 376 } 377 } 378 perimeter.push({'x':x,'y':y}); 379 draw(false,false); 380 return false; 381 } 382} 383 384function close_polygon(){ 385 386 draw(true,true); 387 // Save segmentation and reset perimeter 388 perimeters.push(perimeter); 389 object_colors.push(object_color) 390 object_colors_transparent.push(object_color_transparent) 391 perimeter = new Array(); 392 393} 394 395function add_object_step_1(){ 396 // Close modal 397 $('#modal_1').modal('hide'); 398 399 perimeter_per_object.push(perimeters.length) 400 401 // Open litter tag 402 $('#modal_2').modal(); 403} 404 405function add_object_step_2(){ 406 407 var object_cat = $("#option_cat").val(); 408 //var object_ctx = $("#option2").val(); 409 if (document.querySelector('input[name="contex"]:checked')){ 410 var object_ctx = document.querySelector('input[name="contex"]:checked').value; 411 }else{ 412 alert('Select the context first'); 413 return; 414 } 415 416 if (object_cat == 'base'){ 417 alert('Select the object class first'); 418 return; 419 } 420 421 object_cats.push(object_cat); 422 object_ctxs.push(object_ctx); 423 424 // Close modal 425 $('#modal_2').modal('hide'); 426 427 if(!mobile_device){ 428 // Adding object button 429 object_id = object_cats.length-1; 430 var obj_btn = 431 '<button onclick="edit_object('+object_id+')" style="background-color:'+object_color_transparent+'" id="btn_'+object_id+'"> '+ cat_sorted_by_id[object_cats[object_id]] +' </button>'; 432 $('#object_btn_list').append(obj_btn); 433 } 434
435 // Reset object color 436 var hue = ~~(Math.random() * 360); 437 object_color = "hsla(" + hue + ", 100%, 60%, 1.0)"; 438 object_color_transparent = "hsla(" + hue + ", 100%, 60%, 0.5)"; 439 440 // Add object 441 alert('Object added.'); 442 443} 444 445function edit_object(object_id){ 446 447 object_id_selected = object_id; 448 449 // Show modal with current cat value 450 $("#modal_4").modal(); 451 $('#option_cat_edit').val(object_cats[object_id]).trigger('change.customSelect'); 452 453 // Show ctx current selection 454 obj_ctx_selected = "#ctx_"+object_ctxs[object_id]; 455 $(obj_ctx_selected).prop("checked", true); 456 457} 458 459function delete_object(){ 460 461 $("#modal_4").modal("hide"); 462 463 object_cats.splice(object_id_selected,1); 464 object_ctxs.splice(object_id_selected,1); 465 nr_perimeters_2_delete = perimeter_per_object[object_id_selected+1] - perimeter_per_object[object_id_selected]; 466 perimeters.splice(object_id_selected,nr_perimeters_2_delete); 467 object_colors.splice(object_id_selected,1); 468 object_colors_transparent.splice(object_id_selected,1); 469 470 perimeter_per_object.splice(object_id_selected,1); 471 for(i=object_id_selected; i<perimeter_per_object.length;i++){ 472 perimeter_per_object[i] = perimeter_per_object[i] - nr_perimeters_2_delete; 473 } 474 475 // Update buttons 476 $('#object_btn_list').empty(); 477 for(i =0; i<object_cats.length; i++){ 478 // Adding object button 479 var obj_btn = 480 '<button onclick="edit_object('+i+')" style="background-color:'+object_colors_transparent[i]+'" id="btn_'+i+'"> '+ cat_sorted_by_id[object_cats[i]] +' </button>'; 481 $('#object_btn_list').append(obj_btn); 482 483 } 484 // Draw 485 start(true); 486} 487 488function change_object_class(){ 489 490 // Update object tags 491 object_cats[object_id_selected] = $("#option_cat_edit").val(); 492 object_ctxs[object_id_selected] = document.querySelector('input[name="contex_edit"]:checked').value; 493 494 // Update buttons 495 $('#object_btn_list').empty(); 496 for(i =0; i<object_cats.length; i++){ 497 // Adding object button 498 var obj_btn = 499 '<button onclick="edit_object('+i+')" style="background-color:'+object_colors_transparent[i]+'" id="btn_'+i+'"> '+ cat_sorted_by_id[object_cats[i]] +' </button>'; 500 $('#object_btn_list').append(obj_btn); 501 502 } 503 $("#modal_4").modal("hide"); 504 505} 506 507 508function add_object(){ 509 var object_cat = $("#option_cat").val(); 510 var object_ctx = document.querySelector('input[name="contex"]:checked').value; 511 512 if (object_cat == 'base'){ 513 alert('Select the object class first'); 514 return; 515 } 516 if (object_ctx == 'base'){ 517 alert('Select the context first'); 518 return; 519 } 520 if (perimeter_per_object[perimeter_per_object.length-1] == perimeters.length){ 521 alert('Object not segmented'); 522 return; 523 } 524 525 object_cats.push(object_cat) 526 object_ctxs.push(object_ctx) 527 528 perimeter_per_object.push(perimeters.length) 529 530 alert('Object added.'); 531 532 fill_class_list(); 533 534 // Reset object color 535 var hue = ~~(Math.random() * 360); 536 object_color = "hsla(" + hue + ", 100%, 60%, 1.0)"; 537 object_color_transparent = "hsla(" + hue + ", 100%, 60%, 0.5)"; 538} 539 540function start(with_draw) { 541 542 if(hr_enabled || !multiple_images_available){ 543 url_selected = image_url_o; 544 }else{ 545 url_selected= image_url; 546 } 547 548 loadImage( 549 url_selected, 550 function(img, data) { 551 if (img.type === "error") { 552 console.error("Error loading image " + imageUrl); 553 load_image(); 554 } else { 555 556 img_width = img.width; 557 img_height = img.height; 558 559 console.log(url_selected); 560 // console.log("Exif data: ", data); 561 562 // Scale image if necessary 563 if(!hr_enabled && !multiple_images_available){ 564 if (img_width>img_height){ 565 var s = 640/img_width; 566 }else{ 567 var s = 640/img_height; 568 } 569 img_width = img_width*s; 570 img_height = img_height*s; 571 } 572 573 // Scale polygons if image resolution change (hr toggle) 574 if(canvas.width != img_width){ 575 scale_polygons(img_width/canvas.width,img_height/canvas.height); 576 } 577 578 ctx = canvas.getContext("2d"); 579 canvas.width = img_width; 580 canvas.height = img_height; 581 ctx.drawImage(img, 0, 0, img_width, img_height); 582 583 if(with_draw == true){ 584 redraw();
585 draw(true,false); 586 } 587 } 588 }, 589 { orientation: true} 590 ); 591} 592 593function showTutorial(){ 594 $('#modal_demo').modal(); 595} 596 597function fill_class_list(){ 598 599 $.getJSON("jsondata/metadata.json", function(data) { 600 vals = data.cats_verbose.split(","); 601 cat_ids = data.cat_ids.split(","); 602 603 $.each(cat_ids, function(index, value) { 604 value_int = parseInt(value) 605 cat_sorted_by_id[value_int] = vals[index]; 606 }); 607 608 var option1 = $("#option1"); 609 option1.empty(); 610 option1.append("<option selected value=\"base\">Class</option>"); 611 $.each(vals, function(index, value) { 612 cat_id = cat_ids[index]; 613 option1.append("<option value="+cat_id+">" + value + "</option>"); 614 }); 615 616 // Filling modal 3: 617 var option1_modal = $("#option_cat"); 618 option1_modal.empty(); 619 option1_modal.append("<option selected value=\"base\">Class</option>"); 620 $.each(vals, function(index, value) { 621 cat_id = cat_ids[index]; 622 option1_modal.append("<option value="+cat_id+">" + value + "</option>"); 623 }); 624 625 // Filling modal 4: 626 if (!mobile_device){ 627 var option1_modal_edit = $("#option_cat_edit"); 628 option1_modal_edit.empty(); 629 option1_modal_edit.append("<option selected value=\"base\">Class</option>"); 630 $.each(vals, function(index, value) { 631 cat_id = cat_ids[index]; 632 option1_modal_edit.append("<option value="+cat_id+">" + value + "</option>"); 633 }); 634 } 635 636 637 }); 638 639} 640 641function submit_step_1(){ 642 643 if (object_cats.length==0){ 644 alert('No objects to submit.'); 645 return; 646 } 647 648 $("#modal_3").modal(); 649 650} 651 652function submit_step_2(){ 653 654 // Close modal 655 $('#modal_3').modal('hide'); 656 657 var scene_tags = new Array() 658 var vegetation = document.getElementById("vegetation"); 659 if (vegetation.checked){scene_tags.push(parseInt(vegetation.value));} 660 var road = document.getElementById("road"); 661 if (road.checked){scene_tags.push(parseInt(road.value));} 662 var sand = document.getElementById("sand"); 663 if (sand.checked){scene_tags.push(parseInt(sand.value));} 664 var water = document.getElementById("water"); 665 if (water.checked){scene_tags.push(parseInt(water.value));} 666 var trash = document.getElementById("trash"); 667 if (trash.checked){scene_tags.push(parseInt(trash.value));} 668 var indoor = document.getElementById("indoor"); 669 if (indoor.checked){scene_tags.push(parseInt(indoor.value));} 670 671 vegetation.checked = false; 672 road.checked = false; 673 sand.checked = false; 674 water.checked = false; 675 trash.checked = false; 676 indoor.checked = false; 677 678 var username = document.getElementById("username").value; 679 var email = document.getElementById("email").value; 680 681 // Scale segmentation if needed 682 if(!hr_enabled){ 683 scale_polygons(image_original_width/canvas.width,image_original_height/canvas.height); 684 } 685 686 // Prepare submission data 687 submission = { 688 "id": image_id, 689 'images': [], 690 'scene_annotations': [] 691 } 692 693 image = { 694 "id": image_id, 695 "width": image_original_width, 696 "height": image_original_height, 697 "flickr_url": image_url_o, 698 "flickr_640_url": image_url+' '+username+' '+email, 699 'segmentation': [], 700 } 701 scene_annotation = { 702 "image_id": image_id, 703 "background_ids": scene_tags 704 } 705 submission['scene_annotations'].push(scene_annotation); 706 707 // Adding objects to submssion 708 for (obj_i=0; obj_i<object_cats.length; obj_i++){ 709 710 //Converting and adding polygons to object segmentation 711 segmentations = new Array(); 712 for(seg_j = perimeter_per_object[obj_i]; seg_j<perimeter_per_object[obj_i+1]; seg_j++){ 713 perimeter_j = perimeters[seg_j]; 714 for(i = 0; i<perimeter_j.length; i++){ 715 segmentations.push(perimeter_j[i]['x']); 716 segmentations.push(perimeter_j[i]['y']); 717 } 718 // Adding a flag to signal polygon end/start 719 segmentations.push(-1); 720 } 721 722 const annotation = { 723 "y": segmentations, 724 "category_id": object_cats[obj_i], 725 "context": object_ctxs[obj_i] 726 } 727 image['segmentation'].push(annotation) 728 } 729 730 submission['images'].push(image) 731 732 const submission_stringified = JSON.stringify(submission) 733 734 console.log(submission_stringified) 735 736 // Actual submission using jQuery and AssociateSegmentation endpoint 737 // This will be stored as file at the server and update the DB 738 $.ajax({ 739 url: 'http://178.128.33.132:5901/twirp/v1.taco.annotations.Service/AssociateSegmentation', 740 dataType: 'json', 741 type: 'POST', 742 contentType: 'application/json', 743 data: JSON.stringify(submission),
744 success: alert('Annotation submitted. Thanks good samaritan! One more?') 745 }); 746 747 // Update job counter and save a local copy of annotations 748 if(!mobile_device){ 749 750 // Creating now annotations for user according to COCO format 751 annotations_alla_coco = new Array(); 752 for (obj_i=0; obj_i<object_cats.length; obj_i++){ 753 //Converting and adding polygons to object segmentation 754 segmentations = new Array(); 755 for(seg_j = perimeter_per_object[obj_i]; seg_j<perimeter_per_object[obj_i+1]; seg_j++){ 756 segmentation = new Array(); 757 perimeter_j = perimeters[seg_j]; 758 for(i = 0; i<perimeter_j.length; i++){ 759 segmentation.push(parseInt(perimeter_j[i]['x'])); 760 segmentation.push(parseInt(perimeter_j[i]['y'])); 761 } 762 segmentations.push(segmentation); 763 } 764 765 const annotation = { 766 "id": object_cats.length, 767 "image_id": image_id, 768 "segmentation": segmentations, 769 "category_id": object_cats[obj_i], 770 "context": object_ctxs[obj_i] 771 } 772 773 annotations_alla_coco.push(annotation) 774 } 775 776 // Create annotation to download 777 submission_copy = { 778 'images': [{"id": image_id, "width": image_original_width, "height": image_original_height, 779 "flickr_url": image_url_o, 780 "flickr_640_url": image_url}], 781 'annotations': annotations_alla_coco, 782 'scene_annotations': [scene_annotation], 783 } 784 const submission_copy_stringified = JSON.stringify(submission_copy) 785 // Exports submission copy 786 function download(content, fileName, contentType) { 787 var a = document.createElement("a"); 788 var file = new Blob([content], {type: contentType}); 789 a.href = URL.createObjectURL(file); 790 a.download = fileName; 791 a.click(); 792 } 793 794 var filename = image_id.toString().concat('.json') 795 796 download(submission_copy_stringified, filename, 'text/plain'); 797 798 nr_annotations_reviewed_so_far++; 799 document.getElementById('jobs_counter').innerHTML = " Jobs completed during this session: <code>"+nr_annotations_reviewed_so_far+"</code>"; 800 } 801 802 load_image(); 803 804}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.