001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.sequence; 020 021import icy.image.IcyBufferedImage; 022import icy.type.DataType; 023import icy.util.OMEUtil; 024import icy.util.StringUtil; 025import icy.util.XMLUtil; 026 027import java.awt.Color; 028import java.util.HashSet; 029import java.util.Set; 030 031import org.joda.time.Instant; 032 033import loci.common.services.ServiceException; 034import loci.formats.FormatTools; 035import loci.formats.MetadataTools; 036import loci.formats.ome.OMEXMLMetadataImpl; 037import ome.units.quantity.Time; 038import ome.xml.meta.MetadataRetrieve; 039import ome.xml.meta.OMEXMLMetadata; 040import ome.xml.model.Annotation; 041import ome.xml.model.Channel; 042import ome.xml.model.Dataset; 043import ome.xml.model.Experiment; 044import ome.xml.model.Experimenter; 045import ome.xml.model.ExperimenterGroup; 046import ome.xml.model.Image; 047import ome.xml.model.Instrument; 048import ome.xml.model.OME; 049import ome.xml.model.Pixels; 050import ome.xml.model.Plane; 051import ome.xml.model.ROI; 052import ome.xml.model.StructuredAnnotations; 053import ome.xml.model.XMLAnnotation; 054import ome.xml.model.enums.DimensionOrder; 055import ome.xml.model.primitives.PositiveInteger; 056import ome.xml.model.primitives.Timestamp; 057 058/** 059 * Meta data utilities class.<br> 060 * Basically provide safe access to metadata. 061 * 062 * @author Stephane 063 */ 064public class MetaDataUtil 065{ 066 public static final String DEFAULT_CHANNEL_NAME = "ch "; 067 068 /** 069 * Returns OME root element (create it if needed). 070 */ 071 public static OME getOME(OMEXMLMetadata metaData) 072 { 073 OME result = (OME) metaData.getRoot(); 074 075 if (result == null) 076 { 077 metaData.createRoot(); 078 result = (OME) metaData.getRoot(); 079 } 080 081 return result; 082 } 083 084 /** 085 * @deprecated Use {@link #getOME(OMEXMLMetadata)} instead 086 */ 087 @Deprecated 088 public static OME getOME(OMEXMLMetadataImpl metaData) 089 { 090 return getOME((OMEXMLMetadata) metaData); 091 } 092 093 /** 094 * Returns the number of image series of the specified metaData description. 095 */ 096 public static int getNumSeries(OMEXMLMetadata metaData) 097 { 098 return metaData.getImageCount(); 099 } 100 101 /** 102 * @deprecated Use {@link #getNumSeries(OMEXMLMetadata)} instead 103 */ 104 @Deprecated 105 public static int getNumSerie(loci.formats.ome.OMEXMLMetadata metaData) 106 { 107 return getNumSeries(metaData); 108 } 109 110 /** 111 * @deprecated Use {@link #getNumSeries(OMEXMLMetadata)} instead 112 */ 113 @Deprecated 114 public static int getNumSerie(OMEXMLMetadata metaData) 115 { 116 return getNumSeries(metaData); 117 } 118 119 /** 120 * @deprecated Use {@link #getNumSeries(OMEXMLMetadata)} instead 121 */ 122 @Deprecated 123 public static int getNumSerie(OMEXMLMetadataImpl metaData) 124 { 125 return getNumSerie((OMEXMLMetadata) metaData); 126 } 127 128 /** 129 * Return image series object at specified index for the specified metaData description. 130 */ 131 public static Image getSeries(OMEXMLMetadata metaData, int index) 132 { 133 final OME ome = getOME(metaData); 134 135 if (index < ome.sizeOfImageList()) 136 return ome.getImage(index); 137 138 return null; 139 } 140 141 /** 142 * @deprecated Use {@link #getSeries(OMEXMLMetadata, int)} instead 143 */ 144 @Deprecated 145 public static Image getSerie(OMEXMLMetadata metaData, int index) 146 { 147 return getSeries(metaData, index); 148 } 149 150 /** 151 * @deprecated Use {@link #getSeries(OMEXMLMetadata, int)} instead 152 */ 153 @Deprecated 154 public static Image getSerie(OMEXMLMetadataImpl metaData, int index) 155 { 156 return getSeries(metaData, index); 157 } 158 159 /** 160 * Ensure the image series at specified index exist for the specified metaData description. 161 */ 162 public static Image ensureSeries(OME ome, int index) 163 { 164 // create missing image 165 while (ome.sizeOfImageList() <= index) 166 { 167 final Image img = new Image(); 168 ome.addImage(img); 169 } 170 171 final Image result = ome.getImage(index); 172 173 if (result.getPixels() == null) 174 { 175 final Pixels pix = new Pixels(); 176 // wanted default dimension order 177 pix.setDimensionOrder(DimensionOrder.XYCZT); 178 // create default pixels object 179 result.setPixels(pix); 180 } 181 182 return result; 183 } 184 185 /** 186 * @deprecated Use {@link #ensureSeries(OME, int)} instead 187 */ 188 @Deprecated 189 public static Image ensureSerie(OME ome, int index) 190 { 191 return ensureSeries(ome, index); 192 } 193 194 /** 195 * Set the number of image series for the specified metaData description. 196 */ 197 public static void setNumSeries(OMEXMLMetadata metaData, int num) 198 { 199 final OME ome = getOME(metaData); 200 201 // keep only desired number of image 202 while (ome.sizeOfImageList() > num) 203 ome.removeImage(ome.getImage(ome.sizeOfImageList() - 1)); 204 205 // create missing image 206 ensureSeries(ome, num - 1); 207 } 208 209 /** 210 * @deprecated Use {@link #setNumSeries(OMEXMLMetadata, int)} instead 211 */ 212 @Deprecated 213 public static void setNumSerie(OMEXMLMetadata metaData, int num) 214 { 215 setNumSeries(metaData, num); 216 } 217 218 /** 219 * @deprecated Use {@link #setNumSerie(OMEXMLMetadata, int)} instead 220 */ 221 @Deprecated 222 public static void setNumSerie(OMEXMLMetadataImpl metaData, int num) 223 { 224 setNumSerie((OMEXMLMetadata) metaData, num); 225 } 226 227 /** 228 * Return pixels object at specified index for the specified metaData description. 229 */ 230 public static Pixels getPixels(OME ome, int index) 231 { 232 if (ome != null) 233 { 234 if (index < ome.sizeOfImageList()) 235 return ome.getImage(index).getPixels(); 236 } 237 238 return null; 239 } 240 241 /** 242 * Return pixels object at specified index for the specified metaData description. 243 */ 244 public static Pixels getPixels(OMEXMLMetadata metaData, int index) 245 { 246 return getPixels(getOME(metaData), index); 247 } 248 249 /** 250 * @deprecated Use {@link #getPixels(OMEXMLMetadata, int)} instead 251 */ 252 @Deprecated 253 public static Pixels getPixels(OMEXMLMetadataImpl metaData, int index) 254 { 255 return getPixels((OMEXMLMetadata) metaData, index); 256 } 257 258 /** 259 * Return plane index for the specified T, Z, C position. 260 */ 261 public static int getPlaneIndex(Pixels pix, int t, int z, int c) 262 { 263 // can't compute plane index --> return 0 by default 264 if ((t < 0) || (z < 0) || (c < 0)) 265 return 0; 266 // trivial opti... 267 if ((t == 0) && (z == 0) && (c == 0)) 268 return 0; 269 270 final int sizeT = OMEUtil.getValue(pix.getSizeT(), 0); 271 final int sizeZ = OMEUtil.getValue(pix.getSizeZ(), 0); 272 int sizeC = OMEUtil.getValue(pix.getSizeC(), 0); 273 274 // can't compute plane index --> return 0 by default 275 if ((sizeT == 0) || (sizeZ == 0) || (sizeC == 0)) 276 return 0; 277 278 int adjC = c; 279 280 if (pix.sizeOfChannelList() > 0) 281 { 282 final Channel channel = pix.getChannel(0); 283 if (channel != null) 284 { 285 final int spp = OMEUtil.getValue(channel.getSamplesPerPixel(), 0); 286 // channel are packed in pixel so consider sizeC = 1 287 if ((spp != 0) && (spp == sizeC)) 288 { 289 sizeC = 1; 290 adjC = 0; 291 } 292 } 293 } 294 295 // first try to get index from real plan position 296 final int len = pix.sizeOfPlaneList(); 297 for (int i = 0; i < len; i++) 298 { 299 final Plane plane = pix.getPlane(i); 300 301 // plane found --> return index 302 if ((OMEUtil.getValue(plane.getTheT(), -1) == t) && (OMEUtil.getValue(plane.getTheZ(), -1) == z) 303 && (OMEUtil.getValue(plane.getTheC(), -1) == c)) 304 return i; 305 } 306 307 DimensionOrder dimOrder = pix.getDimensionOrder(); 308 // use default dimension order 309 if (dimOrder == null) 310 dimOrder = DimensionOrder.XYCZT; 311 312 // use computed method 313 return FormatTools.getIndex(dimOrder.getValue(), sizeZ, sizeC, sizeT, sizeZ * sizeC * sizeT, z, adjC, t); 314 } 315 316 public static Plane getPlane(Pixels pix, int index) 317 { 318 if (pix != null) 319 { 320 if (index < pix.sizeOfPlaneList()) 321 return pix.getPlane(index); 322 } 323 324 return null; 325 } 326 327 /** 328 * Return plane object for the specified T, Z, C position. 329 */ 330 public static Plane getPlane(Pixels pix, int t, int z, int c) 331 { 332 return getPlane(pix, getPlaneIndex(pix, t, z, c)); 333 } 334 335 /** 336 * Ensure the plane at specified index exist for the specified Pixels object. 337 */ 338 public static Plane ensurePlane(Pixels pix, int index) 339 { 340 // create missing plane 341 while (pix.sizeOfPlaneList() <= index) 342 pix.addPlane(new Plane()); 343 344 return pix.getPlane(index); 345 } 346 347 /** 348 * Ensure the plane at specified T, Z, C position exist for the specified Pixels object. 349 */ 350 public static Plane ensurePlane(Pixels pix, int t, int z, int c) 351 { 352 return ensurePlane(pix, getPlaneIndex(pix, t, z, c)); 353 } 354 355 /** 356 * Remove the plane at specified position. 357 * 358 * @return <code>true</code> if the operation succeed, <code>false</code> otherwise 359 */ 360 public static boolean removePlane(Image img, int index) 361 { 362 final Pixels pix = img.getPixels(); 363 if (pix == null) 364 return false; 365 366 final int numPlane = pix.sizeOfPlaneList(); 367 368 // single plane information or no plane here --> return false 369 if ((numPlane <= 1) || (index >= numPlane)) 370 return false; 371 372 final Plane plane = getPlane(pix, index); 373 374 // remove plane 375 pix.removePlane(plane); 376 377 // remove associated annotation 378 for (int i = 0; i < plane.sizeOfLinkedAnnotationList(); i++) 379 img.unlinkAnnotation(plane.getLinkedAnnotation(i)); 380 381 // clean some data 382 if (pix.sizeOfBinDataList() == numPlane) 383 pix.removeBinData(pix.getBinData(index)); 384 if (pix.sizeOfTiffDataList() == numPlane) 385 pix.removeTiffData(pix.getTiffData(index)); 386 387 return true; 388 } 389 390 /** 391 * Remove the plane at specified position. 392 * 393 * @return <code>true</code> if the operation succeed, <code>false</code> otherwise 394 */ 395 public static boolean removePlane(Image img, int t, int z, int c) 396 { 397 final Pixels pix = img.getPixels(); 398 if (pix == null) 399 return false; 400 401 return removePlane(img, getPlaneIndex(pix, t, z, c)); 402 } 403 404 /** 405 * Remove the plane at specified position. 406 * 407 * @return <code>true</code> if the operation succeed, <code>false</code> otherwise 408 */ 409 public static boolean removePlane(OMEXMLMetadata metadata, int series, int t, int z, int c) 410 { 411 final Image img = getSeries(metadata, series); 412 if (img == null) 413 return false; 414 415 return removePlane(img, t, z, c); 416 } 417 418 /** 419 * @deprecated Use {@link #removePlane(OMEXMLMetadata, int, int, int, int)} instead 420 */ 421 @Deprecated 422 public static boolean removePlane(OMEXMLMetadataImpl metadata, int series, int t, int z, int c) 423 { 424 return removePlane((OMEXMLMetadata) metadata, series, t, z, c); 425 } 426 427 /** 428 * Remove planes at given position 429 * 430 * @param posT 431 * T position where we want to remove metadata (-1 for all) 432 * @param posZ 433 * Z position where we want to remove metadata (-1 for all) 434 * @param posC 435 * C position where we want to remove metadata (-1 for all) 436 */ 437 public static void removePlanes(OMEXMLMetadata metadata, int series, int posT, int posZ, int posC) 438 { 439 final int minT, maxT; 440 final int minZ, maxZ; 441 final int minC, maxC; 442 443 if (posT < 0) 444 { 445 minT = 0; 446 maxT = getSizeT(metadata, series) - 1; 447 } 448 else 449 { 450 minT = posT; 451 maxT = posT; 452 } 453 if (posZ < 0) 454 { 455 minZ = 0; 456 maxZ = getSizeZ(metadata, series) - 1; 457 } 458 else 459 { 460 minZ = posZ; 461 maxZ = posZ; 462 } 463 if (posC < 0) 464 { 465 minC = 0; 466 maxC = getSizeC(metadata, series) - 1; 467 } 468 else 469 { 470 minC = posC; 471 maxC = posC; 472 } 473 474 for (int t = minT; t <= maxT; t++) 475 for (int z = minZ; z <= maxZ; z++) 476 for (int c = minC; c <= maxC; c++) 477 MetaDataUtil.removePlane(metadata, 0, t, z, c); 478 } 479 480 /** 481 * @deprecated Use {@link #removePlanes(OMEXMLMetadata, int, int, int, int)} instead 482 */ 483 @Deprecated 484 public static void removePlanes(OMEXMLMetadataImpl metadata, int series, int posT, int posZ, int posC) 485 { 486 removePlanes((OMEXMLMetadata) metadata, series, posT, posZ, posC); 487 } 488 489 /** 490 * Returns the data type of the specified image series. 491 */ 492 public static DataType getDataType(OMEXMLMetadata metaData, int series) 493 { 494 final Pixels pix = getPixels(metaData, series); 495 496 if (pix != null) 497 return DataType.getDataTypeFromPixelType(pix.getType()); 498 499 // assume byte by default 500 return DataType.UBYTE; 501 } 502 503 /** 504 * @deprecated Use {@link #getDataType(OMEXMLMetadata, int)} instead 505 */ 506 @Deprecated 507 public static DataType getDataType(OMEXMLMetadataImpl metaData, int series) 508 { 509 return getDataType((OMEXMLMetadata) metaData, series); 510 } 511 512 /** 513 * Returns the width (sizeX) of the specified image series. 514 */ 515 public static int getSizeX(OMEXMLMetadata metaData, int series) 516 { 517 final Pixels pix = getPixels(metaData, series); 518 519 if (pix != null) 520 return OMEUtil.getValue(pix.getSizeX(), 0); 521 522 return 0; 523 } 524 525 /** 526 * @deprecated Use {@link #getSizeX(OMEXMLMetadata, int)} instead 527 */ 528 @Deprecated 529 public static int getSizeX(OMEXMLMetadataImpl metaData, int series) 530 { 531 return getSizeX((OMEXMLMetadata) metaData, series); 532 } 533 534 /** 535 * Returns the height (sizeY) of the specified image series. 536 */ 537 public static int getSizeY(OMEXMLMetadata metaData, int series) 538 { 539 final Pixels pix = getPixels(metaData, series); 540 541 if (pix != null) 542 return OMEUtil.getValue(pix.getSizeY(), 0); 543 544 return 0; 545 } 546 547 /** 548 * @deprecated Use {@link #getSizeY(OMEXMLMetadata, int)} instead 549 */ 550 @Deprecated 551 public static int getSizeY(OMEXMLMetadataImpl metaData, int series) 552 { 553 return getSizeY((OMEXMLMetadata) metaData, series); 554 } 555 556 /** 557 * Returns the number of channel (sizeC) of the specified image series. 558 */ 559 public static int getSizeC(OMEXMLMetadata metaData, int series) 560 { 561 final Pixels pix = getPixels(metaData, series); 562 563 if (pix != null) 564 return OMEUtil.getValue(pix.getSizeC(), 0); 565 566 return 0; 567 } 568 569 /** 570 * @deprecated Use {@link #getSizeC(OMEXMLMetadata, int)} instead 571 */ 572 @Deprecated 573 public static int getSizeC(OMEXMLMetadataImpl metaData, int series) 574 { 575 return getSizeC((OMEXMLMetadata) metaData, series); 576 } 577 578 /** 579 * Returns the depth (sizeZ) of the specified image series. 580 */ 581 public static int getSizeZ(OMEXMLMetadata metaData, int series) 582 { 583 final Pixels pix = getPixels(metaData, series); 584 585 if (pix != null) 586 return OMEUtil.getValue(pix.getSizeZ(), 0); 587 588 return 0; 589 } 590 591 /** 592 * @deprecated Use {@link #getSizeZ(OMEXMLMetadata, int)} instead 593 */ 594 @Deprecated 595 public static int getSizeZ(OMEXMLMetadataImpl metaData, int series) 596 { 597 return getSizeZ((OMEXMLMetadata) metaData, series); 598 } 599 600 /** 601 * Returns the number of frame (sizeT) of the specified Pixels object. 602 */ 603 private static int getSizeT(Pixels pix) 604 { 605 return OMEUtil.getValue(pix.getSizeT(), 0); 606 } 607 608 /** 609 * Returns the number of frame (sizeT) of the specified image series. 610 */ 611 public static int getSizeT(OMEXMLMetadata metaData, int series) 612 { 613 final Pixels pix = getPixels(metaData, series); 614 615 if (pix != null) 616 return getSizeT(pix); 617 618 return 0; 619 } 620 621 /** 622 * @deprecated Use {@link #getSizeT(OMEXMLMetadata, int)} instead 623 */ 624 @Deprecated 625 public static int getSizeT(OMEXMLMetadataImpl metaData, int series) 626 { 627 return getSizeT((OMEXMLMetadata) metaData, series); 628 } 629 630 /** 631 * Returns the total data size (in bytes) of the specified image series. 632 */ 633 public static long getDataSize(OMEXMLMetadata metaData, int series) 634 { 635 return getDataSize(metaData, series, 0); 636 } 637 638 /** 639 * Returns the total data size (in bytes) of the specified image series 640 * for the given resolution (0 = full, 1 = 1/2, ...) 641 */ 642 public static long getDataSize(OMEXMLMetadata metaData, int series, int resolution) 643 { 644 return getDataSize(metaData, series, resolution, getSizeZ(metaData, series), getSizeT(metaData, series)); 645 } 646 647 /** 648 * Returns the total data size (in bytes) of the specified image series 649 * for the given resolution (0 = full, 1 = 1/2, ...) and size informations 650 */ 651 public static long getDataSize(OMEXMLMetadata metaData, int series, int resolution, int sizeZ, int sizeT) 652 { 653 return getDataSize(metaData, series, resolution, sizeZ, sizeT, getSizeC(metaData, series)); 654 } 655 656 /** 657 * Returns the total data size (in bytes) of the specified image series 658 * for the given resolution (0 = full, 1 = 1/2, ...) and size informations 659 */ 660 public static long getDataSize(OMEXMLMetadata metaData, int series, int resolution, int sizeZ, int sizeT, int sizeC) 661 { 662 final Pixels pix = getPixels(metaData, series); 663 664 if (pix != null) 665 { 666 long sizeXY = (long) OMEUtil.getValue(pix.getSizeX(), 0) * (long) OMEUtil.getValue(pix.getSizeY(), 0); 667 668 if (resolution > 0) 669 sizeXY /= Math.pow(4d, resolution); 670 671 return sizeXY * sizeC * sizeZ * sizeT * DataType.getDataTypeFromPixelType(pix.getType()).getSize(); 672 } 673 674 return 0L; 675 } 676 677 /** 678 * Sets the data type of the specified image series. 679 */ 680 public static void setDataType(OMEXMLMetadata metaData, int series, DataType dataType) 681 { 682 metaData.setPixelsType(dataType.toPixelType(), series); 683 } 684 685 /** 686 * @deprecated Use {@link #setDataType(OMEXMLMetadata, int, DataType)} instead 687 */ 688 @Deprecated 689 public static void setDataType(OMEXMLMetadataImpl metaData, int series, DataType dataType) 690 { 691 setDataType((OMEXMLMetadata) metaData, series, dataType); 692 } 693 694 /** 695 * Sets the width (sizeX) of the specified image series (need to be >= 1). 696 */ 697 public static void setSizeX(OMEXMLMetadata metaData, int series, int sizeX) 698 { 699 metaData.setPixelsSizeX(OMEUtil.getPositiveInteger(sizeX), series); 700 } 701 702 /** 703 * @deprecated Use {@link #setSizeX(OMEXMLMetadata, int, int)} instead 704 */ 705 @Deprecated 706 public static void setSizeX(OMEXMLMetadataImpl metaData, int series, int sizeX) 707 { 708 setSizeX((OMEXMLMetadata) metaData, series, sizeX); 709 } 710 711 /** 712 * Sets the height (sizeY) of the specified image series (need to be >= 1). 713 */ 714 public static void setSizeY(OMEXMLMetadata metaData, int series, int sizeY) 715 { 716 metaData.setPixelsSizeY(OMEUtil.getPositiveInteger(sizeY), series); 717 } 718 719 /** 720 * @deprecated Use {@link #setSizeY(OMEXMLMetadata, int, int)} instead 721 */ 722 @Deprecated 723 public static void setSizeY(OMEXMLMetadataImpl metaData, int series, int sizeY) 724 { 725 setSizeY((OMEXMLMetadata) metaData, series, sizeY); 726 } 727 728 /** 729 * Sets the number of channel (sizeC) of the specified image series (need to be >= 1). 730 */ 731 public static void setSizeC(OMEXMLMetadata metaData, int series, int sizeC) 732 { 733 metaData.setPixelsSizeC(OMEUtil.getPositiveInteger(sizeC), series); 734 } 735 736 /** 737 * @deprecated Use {@link #setSizeC(OMEXMLMetadata, int, int)} instead 738 */ 739 @Deprecated 740 public static void setSizeC(OMEXMLMetadataImpl metaData, int series, int sizeC) 741 { 742 setSizeC((OMEXMLMetadata) metaData, series, sizeC); 743 } 744 745 /** 746 * Sets the depth (sizeZ) of the specified image series (need to be >= 1). 747 */ 748 public static void setSizeZ(OMEXMLMetadata metaData, int series, int sizeZ) 749 { 750 metaData.setPixelsSizeZ(OMEUtil.getPositiveInteger(sizeZ), series); 751 } 752 753 /** 754 * @deprecated Use {@link #setSizeZ(OMEXMLMetadata, int, int)} instead 755 */ 756 @Deprecated 757 public static void setSizeZ(OMEXMLMetadataImpl metaData, int series, int sizeZ) 758 { 759 setSizeZ((OMEXMLMetadata) metaData, series, sizeZ); 760 } 761 762 /** 763 * Sets the number of frame (sizeT) of the specified image series (need to be >= 1). 764 */ 765 public static void setSizeT(OMEXMLMetadata metaData, int series, int sizeT) 766 { 767 metaData.setPixelsSizeT(OMEUtil.getPositiveInteger(sizeT), series); 768 } 769 770 /** 771 * @deprecated Use {@link #setSizeT(OMEXMLMetadata, int, int)} instead 772 */ 773 @Deprecated 774 public static void setSizeT(OMEXMLMetadataImpl metaData, int series, int sizeT) 775 { 776 setSizeT((OMEXMLMetadata) metaData, series, sizeT); 777 } 778 779 /** 780 * Returns the id of the specified image series. 781 */ 782 public static String getImageID(OMEXMLMetadata metaData, int series) 783 { 784 final Image img = getSeries(metaData, series); 785 786 if (img != null) 787 return StringUtil.getValue(img.getID(), ""); 788 789 return ""; 790 } 791 792 /** 793 * @deprecated Use {@link #getImageID(OMEXMLMetadata, int)} instead 794 */ 795 @Deprecated 796 public static String getImageID(OMEXMLMetadataImpl metaData, int series) 797 { 798 return getImageID((OMEXMLMetadata) metaData, series); 799 } 800 801 /** 802 * Set the id of the specified image series. 803 */ 804 public static void setImageID(OMEXMLMetadata metaData, int series, String value) 805 { 806 metaData.setImageID(value, series); 807 } 808 809 /** 810 * @deprecated Use {@link #setImageID(OMEXMLMetadata, int, String)} instead 811 */ 812 @Deprecated 813 public static void setImageID(OMEXMLMetadataImpl metaData, int series, String value) 814 { 815 setImageID((OMEXMLMetadata) metaData, series, value); 816 } 817 818 /** 819 * Returns the name of the specified image series. 820 */ 821 public static String getName(OMEXMLMetadata metaData, int series) 822 { 823 final Image img = getSeries(metaData, series); 824 825 if (img != null) 826 return StringUtil.getValue(img.getName(), ""); 827 828 return ""; 829 } 830 831 /** 832 * @deprecated Use {@link #getName(OMEXMLMetadata, int)} instead 833 */ 834 @Deprecated 835 public static String getName(OMEXMLMetadataImpl metaData, int series) 836 { 837 return getName((OMEXMLMetadata) metaData, series); 838 } 839 840 /** 841 * Set the name of the specified image series. 842 */ 843 public static void setName(OMEXMLMetadata metaData, int series, String value) 844 { 845 metaData.setImageName(value, series); 846 } 847 848 /** 849 * @deprecated Use {@link #setName(OMEXMLMetadata, int, String)} instead 850 */ 851 @Deprecated 852 public static void setName(OMEXMLMetadataImpl metaData, int series, String value) 853 { 854 setName((OMEXMLMetadata) metaData, series, value); 855 } 856 857 /** 858 * Returns X pixel size (in µm) of the specified image series. 859 */ 860 public static double getPixelSizeX(OMEXMLMetadata metaData, int series, double defaultValue) 861 { 862 final Pixels pix = getPixels(metaData, series); 863 864 if (pix != null) 865 return OMEUtil.getValue(pix.getPhysicalSizeX(), defaultValue); 866 867 return defaultValue; 868 } 869 870 /** 871 * @deprecated Use {@link #getPixelSizeX(OMEXMLMetadata, int, double)} instead 872 */ 873 @Deprecated 874 public static double getPixelSizeX(OMEXMLMetadataImpl metaData, int series, double defaultValue) 875 { 876 return getPixelSizeX((OMEXMLMetadata) metaData, series, defaultValue); 877 } 878 879 /** 880 * Returns Y pixel size (in µm) of the specified image series. 881 */ 882 public static double getPixelSizeY(OMEXMLMetadata metaData, int series, double defaultValue) 883 { 884 final Pixels pix = getPixels(metaData, series); 885 886 if (pix != null) 887 return OMEUtil.getValue(pix.getPhysicalSizeY(), defaultValue); 888 889 return defaultValue; 890 } 891 892 /** 893 * @deprecated Use {@link #getPixelSizeY(OMEXMLMetadata, int, double)} instead 894 */ 895 @Deprecated 896 public static double getPixelSizeY(OMEXMLMetadataImpl metaData, int series, double defaultValue) 897 { 898 return getPixelSizeY((OMEXMLMetadata) metaData, series, defaultValue); 899 } 900 901 /** 902 * Returns Z pixel size (in µm) of the specified image series. 903 */ 904 public static double getPixelSizeZ(OMEXMLMetadata metaData, int series, double defaultValue) 905 { 906 final Pixels pix = getPixels(metaData, series); 907 908 if (pix != null) 909 return OMEUtil.getValue(pix.getPhysicalSizeZ(), defaultValue); 910 911 return defaultValue; 912 } 913 914 /** 915 * @deprecated Use {@link #getPixelSizeZ(OMEXMLMetadata, int, double)} instead 916 */ 917 @Deprecated 918 public static double getPixelSizeZ(OMEXMLMetadataImpl metaData, int series, double defaultValue) 919 { 920 return getPixelSizeZ((OMEXMLMetadata) metaData, series, defaultValue); 921 } 922 923 /** 924 * Computes and returns the T time interval (in second) from internal time positions.<br> 925 * If there is no internal time positions <code>0d</code> is returned. 926 */ 927 public static double getTimeIntervalFromTimePositions(OMEXMLMetadata metaData, int series) 928 { 929 final Pixels pix = getPixels(metaData, series); 930 931 // try to compute time interval from time position 932 if (pix != null) 933 return computeTimeIntervalFromTimePosition(pix); 934 935 return 0d; 936 } 937 938 /** 939 * @deprecated Use {@link #getTimeIntervalFromTimePositions(OMEXMLMetadata, int)} instead 940 */ 941 @Deprecated 942 public static double getTimeIntervalFromTimePositions(OMEXMLMetadataImpl metaData, int series) 943 { 944 return getTimeIntervalFromTimePositions((OMEXMLMetadata) metaData, series); 945 } 946 947 /** 948 * Returns T time interval (in second) for the specified image series. 949 */ 950 private static double getTimeInterval(Pixels pix, double defaultValue) 951 { 952 final Time timeInc = pix.getTimeIncrement(); 953 954 if (timeInc != null) 955 return OMEUtil.getValue(timeInc, defaultValue); 956 957 return defaultValue; 958 } 959 960 /** 961 * Returns T time interval (in second) for the specified image series. 962 */ 963 public static double getTimeInterval(OMEXMLMetadata metaData, int series, double defaultValue) 964 { 965 final Pixels pix = getPixels(metaData, series); 966 967 if (pix != null) 968 return getTimeInterval(pix, defaultValue); 969 970 return defaultValue; 971 } 972 973 /** 974 * @deprecated Use {@link #getTimeInterval(OMEXMLMetadata, int, double)} instead 975 */ 976 @Deprecated 977 public static double getTimeInterval(OMEXMLMetadataImpl metaData, int series, double defaultValue) 978 { 979 return getTimeInterval((OMEXMLMetadata) metaData, series, defaultValue); 980 } 981 982 /** 983 * Set X pixel size (in µm) of the specified image series. 984 */ 985 public static void setPixelSizeX(OMEXMLMetadata metaData, int series, double value) 986 { 987 metaData.setPixelsPhysicalSizeX(OMEUtil.getLength(value), series); 988 } 989 990 /** 991 * @deprecated Use {@link #setPixelSizeX(OMEXMLMetadata, int, double)} instead 992 */ 993 @Deprecated 994 public static void setPixelSizeX(OMEXMLMetadataImpl metaData, int series, double value) 995 { 996 setPixelSizeX((OMEXMLMetadata) metaData, series, value); 997 } 998 999 /** 1000 * Set Y pixel size (in µm) of the specified image series. 1001 */ 1002 public static void setPixelSizeY(OMEXMLMetadata metaData, int series, double value) 1003 { 1004 metaData.setPixelsPhysicalSizeY(OMEUtil.getLength(value), series); 1005 } 1006 1007 /** 1008 * @deprecated Use {@link #setPixelSizeY(OMEXMLMetadata, int, double)} instead 1009 */ 1010 @Deprecated 1011 public static void setPixelSizeY(OMEXMLMetadataImpl metaData, int series, double value) 1012 { 1013 setPixelSizeY((OMEXMLMetadata) metaData, series, value); 1014 } 1015 1016 /** 1017 * Set Z pixel size (in µm) of the specified image series. 1018 */ 1019 public static void setPixelSizeZ(OMEXMLMetadata metaData, int series, double value) 1020 { 1021 metaData.setPixelsPhysicalSizeZ(OMEUtil.getLength(value), series); 1022 } 1023 1024 /** 1025 * @deprecated Use {@link #setPixelSizeZ(OMEXMLMetadata, int, double)} instead 1026 */ 1027 @Deprecated 1028 public static void setPixelSizeZ(OMEXMLMetadataImpl metaData, int series, double value) 1029 { 1030 setPixelSizeZ((OMEXMLMetadata) metaData, series, value); 1031 } 1032 1033 /** 1034 * Set T time resolution (in second) of the specified image series. 1035 */ 1036 public static void setTimeInterval(OMEXMLMetadata metaData, int series, double value) 1037 { 1038 metaData.setPixelsTimeIncrement(OMEUtil.getTime(value), series); 1039 } 1040 1041 /** 1042 * @deprecated Use {@link #setTimeInterval(OMEXMLMetadata, int, double)} instead 1043 */ 1044 @Deprecated 1045 public static void setTimeInterval(OMEXMLMetadataImpl metaData, int series, double value) 1046 { 1047 setTimeInterval((OMEXMLMetadata) metaData, series, value); 1048 } 1049 1050 /** 1051 * Returns the X field position (in µm) for the image at the specified Z, T, C position. 1052 */ 1053 public static double getPositionX(OMEXMLMetadata metaData, int series, int t, int z, int c, double defaultValue) 1054 { 1055 final Pixels pix = getPixels(metaData, series); 1056 1057 if (pix != null) 1058 { 1059 final Plane plane = getPlane(pix, t, z, c); 1060 1061 if (plane != null) 1062 return OMEUtil.getValue(plane.getPositionX(), defaultValue); 1063 } 1064 1065 return defaultValue; 1066 } 1067 1068 /** 1069 * Returns the Y field position (in µm) for the image at the specified Z, T, C position. 1070 */ 1071 public static double getPositionY(OMEXMLMetadata metaData, int series, int t, int z, int c, double defaultValue) 1072 { 1073 final Pixels pix = getPixels(metaData, series); 1074 1075 if (pix != null) 1076 { 1077 final Plane plane = getPlane(pix, t, z, c); 1078 1079 if (plane != null) 1080 return OMEUtil.getValue(plane.getPositionY(), defaultValue); 1081 } 1082 1083 return defaultValue; 1084 } 1085 1086 /** 1087 * Returns the Z field position (in µm) for the image at the specified Z, T, C position. 1088 */ 1089 public static double getPositionZ(OMEXMLMetadata metaData, int series, int t, int z, int c, double defaultValue) 1090 { 1091 final Pixels pix = getPixels(metaData, series); 1092 1093 if (pix != null) 1094 { 1095 final Plane plane = getPlane(pix, t, z, c); 1096 1097 if (plane != null) 1098 return OMEUtil.getValue(plane.getPositionZ(), defaultValue); 1099 } 1100 1101 return defaultValue; 1102 } 1103 1104 /** 1105 * @same as {@link #getTimeStamp(OMEXMLMetadata, int, long)} 1106 */ 1107 public static double getPositionT(OMEXMLMetadata metaData, int series, long defaultValue) 1108 { 1109 return getTimeStamp(metaData, series, defaultValue); 1110 } 1111 1112 /** 1113 * Returns the time stamp (elapsed milliseconds from the Java epoch of 1970-01-01 T00:00:00Z) for the specified image. 1114 */ 1115 public static long getTimeStamp(OMEXMLMetadata metaData, int series, long defaultValue) 1116 { 1117 final Image img = getSeries(metaData, series); 1118 1119 if (img != null) 1120 { 1121 final Timestamp time = img.getAcquisitionDate(); 1122 1123 if (time != null) 1124 return time.asInstant().getMillis(); 1125 } 1126 1127 return defaultValue; 1128 } 1129 1130 /** 1131 * Returns the time position offset (in second) relative to first image for the image at the specified Z, T, C position. 1132 */ 1133 private static double getPositionTOffset(Pixels pix, int t, int z, int c, double defaultValue) 1134 { 1135 double result = -1d; 1136 final Plane plane = getPlane(pix, t, z, c); 1137 1138 if (plane != null) 1139 result = OMEUtil.getValue(plane.getDeltaT(), -1d); 1140 1141 // got it from DeltaT 1142 if (result != -1d) 1143 return result; 1144 1145 // try from time interval instead 1146 result = getTimeInterval(pix, -1d); 1147 1148 // we were able to get time interval ? just multiply it by T index 1149 if (result != -1d) 1150 return result * t; 1151 1152 return defaultValue; 1153 } 1154 1155 /** 1156 * Returns the time position offset (in second) relative to first image for the image at the specified Z, T, C position. 1157 */ 1158 public static double getPositionTOffset(OMEXMLMetadata metaData, int series, int t, int z, int c, 1159 double defaultValue) 1160 { 1161 final Pixels pix = getPixels(metaData, series); 1162 1163 if (pix != null) 1164 return getPositionTOffset(pix, t, z, c, defaultValue); 1165 1166 return defaultValue; 1167 } 1168 1169 /** 1170 * @deprecated USe {@link #getPositionTOffset(OMEXMLMetadata, int, int, int, int, double)} instead 1171 */ 1172 @Deprecated 1173 public static double getPositionT(OMEXMLMetadata metaData, int series, int t, int z, int c, double defaultValue) 1174 { 1175 return getPositionTOffset(metaData, series, t, z, c, defaultValue); 1176 } 1177 1178 /** 1179 * @deprecated USe {@link #getPositionTOffset(OMEXMLMetadata, int, int, int, int, double)} instead 1180 */ 1181 @Deprecated 1182 public static double getTimePosition(OMEXMLMetadata metaData, int series, int t, int z, int c, double defaultValue) 1183 { 1184 return getPositionTOffset(metaData, series, t, z, c, defaultValue); 1185 } 1186 1187 /** 1188 * Computes time interval (in second) from the time position informations.<br> 1189 * Returns <code>0d</code> if time position informations are missing ot if we have only 1 frame in the image. 1190 */ 1191 private static double computeTimeIntervalFromTimePosition(Pixels pix) 1192 { 1193 final int sizeT = getSizeT(pix); 1194 1195 if (sizeT <= 1) 1196 return 0d; 1197 1198 double result = 0d; 1199 double last = -1d; 1200 int lastT = 0; 1201 int num = 0; 1202 1203 for (int t = 0; t < sizeT; t++) 1204 { 1205 final Plane plane = getPlane(pix, t, 0, 0); 1206 1207 if (plane != null) 1208 { 1209 final double timePos = OMEUtil.getValue(plane.getDeltaT(), Double.NaN); 1210 1211 if (!Double.isNaN(timePos)) 1212 { 1213 if (last != -1d) 1214 { 1215 // get delta 1216 result += (timePos - last) / (t - lastT); 1217 num++; 1218 } 1219 1220 last = timePos; 1221 lastT = t; 1222 } 1223 } 1224 } 1225 1226 // we need at least 1 delta 1227 if (num == 0) 1228 return 0d; 1229 1230 return result / num; 1231 } 1232 1233 /** 1234 * Sets the X field position (in µm) for the image at the specified Z, T, C position. 1235 */ 1236 public static void setPositionX(OMEXMLMetadata metaData, int series, int t, int z, int c, double value) 1237 { 1238 final Pixels pix = getPixels(metaData, series); 1239 1240 if (pix != null) 1241 { 1242 final Plane plane = ensurePlane(pix, t, z, c); 1243 1244 if (plane != null) 1245 plane.setPositionX(OMEUtil.getLength(value)); 1246 } 1247 } 1248 1249 /** 1250 * Sets the Y field position (in µm) for the image at the specified Z, T, C position. 1251 */ 1252 public static void setPositionY(OMEXMLMetadata metaData, int series, int t, int z, int c, double value) 1253 { 1254 final Pixels pix = getPixels(metaData, series); 1255 1256 if (pix != null) 1257 { 1258 final Plane plane = ensurePlane(pix, t, z, c); 1259 1260 if (plane != null) 1261 plane.setPositionY(OMEUtil.getLength(value)); 1262 } 1263 } 1264 1265 /** 1266 * Sets the Z field position (in µm) for the image at the specified Z, T, C position. 1267 */ 1268 public static void setPositionZ(OMEXMLMetadata metaData, int series, int t, int z, int c, double value) 1269 { 1270 final Pixels pix = getPixels(metaData, series); 1271 1272 if (pix != null) 1273 { 1274 final Plane plane = ensurePlane(pix, t, z, c); 1275 1276 if (plane != null) 1277 plane.setPositionZ(OMEUtil.getLength(value)); 1278 } 1279 } 1280 1281 /** 1282 * Same as {@link #setTimeStamp(OMEXMLMetadata, int, long)} 1283 */ 1284 public static void setPositionT(OMEXMLMetadata metaData, int series, long value) 1285 { 1286 setTimeStamp(metaData, series, value); 1287 } 1288 1289 /** 1290 * Sets the time stamp (elapsed milliseconds from the Java epoch of 1970-01-01 T00:00:00Z) for the specified image. 1291 */ 1292 public static void setTimeStamp(OMEXMLMetadata metaData, int series, long value) 1293 { 1294 final Image img = getSeries(metaData, series); 1295 1296 if (img != null) 1297 img.setAcquisitionDate(new Timestamp(new Instant(value))); 1298 } 1299 1300 /** 1301 * Sets the time position offset (in second) relative to the first image for the image at the specified Z, T, C position. 1302 */ 1303 private static void setPositionTOffset(Pixels pix, int t, int z, int c, double value) 1304 { 1305 final Plane plane = getPlane(pix, t, z, c); 1306 1307 if (plane != null) 1308 plane.setDeltaT(OMEUtil.getTime(value)); 1309 } 1310 1311 /** 1312 * Sets the time position offset (in second) relative to the first image for the image at the specified Z, T, C position. 1313 */ 1314 public static void setPositionTOffset(OMEXMLMetadata metaData, int series, int t, int z, int c, double value) 1315 { 1316 final Pixels pix = getPixels(metaData, series); 1317 1318 if (pix != null) 1319 setPositionTOffset(pix, t, z, c, value); 1320 } 1321 1322 /** 1323 * Get default name for specified channel. 1324 */ 1325 public static String getDefaultChannelName(int channel) 1326 { 1327 return DEFAULT_CHANNEL_NAME + channel; 1328 } 1329 1330 /** 1331 * Returns the number of channel for the specified image series in metaData description. 1332 */ 1333 public static int getNumChannel(OMEXMLMetadata metaData, int series) 1334 { 1335 final Pixels pix = getPixels(metaData, series); 1336 1337 if (pix != null) 1338 return pix.sizeOfChannelList(); 1339 1340 return 0; 1341 } 1342 1343 /** 1344 * @deprecated Use {@link #getNumChannel(OMEXMLMetadata, int)} instead 1345 */ 1346 @Deprecated 1347 public static int getNumChannel(OMEXMLMetadataImpl metaData, int series) 1348 { 1349 return getNumChannel((OMEXMLMetadata) metaData, series); 1350 } 1351 1352 /** 1353 * Return channel object at specified index for the specified image series. 1354 */ 1355 public static Channel getChannel(OMEXMLMetadata metaData, int series, int index) 1356 { 1357 final Pixels pix = getPixels(metaData, series); 1358 1359 if ((pix != null) && (index < pix.sizeOfChannelList())) 1360 return pix.getChannel(index); 1361 1362 return null; 1363 } 1364 1365 /** 1366 * @deprecated Use {@link #getChannel(OMEXMLMetadata, int, int)} instead 1367 */ 1368 @Deprecated 1369 public static Channel getChannel(OMEXMLMetadataImpl metaData, int series, int index) 1370 { 1371 return getChannel((OMEXMLMetadata) metaData, series, index); 1372 } 1373 1374 /** 1375 * Ensure the channel at specified index exist for the specified image series. 1376 */ 1377 public static Channel ensureChannel(OMEXMLMetadata metaData, int series, int index) 1378 { 1379 final Pixels pix = getPixels(metaData, series); 1380 1381 if (pix != null) 1382 return ensureChannel(pix, index); 1383 1384 return null; 1385 } 1386 1387 /** 1388 * @deprecated Use {@link #ensureChannel(OMEXMLMetadata, int, int)} instead 1389 */ 1390 @Deprecated 1391 public static Channel ensureChannel(OMEXMLMetadataImpl metaData, int series, int index) 1392 { 1393 return ensureChannel((OMEXMLMetadata) metaData, series, index); 1394 } 1395 1396 /** 1397 * Ensure the channel at specified index exist for the specified image series. 1398 */ 1399 public static Channel ensureChannel(Pixels pix, int index) 1400 { 1401 // create missing channel 1402 while (pix.sizeOfChannelList() <= index) 1403 pix.addChannel(new Channel()); 1404 1405 return pix.getChannel(index); 1406 } 1407 1408 /** 1409 * Remove a channel for the specified image series. 1410 */ 1411 public static void removeChannel(OMEXMLMetadata metaData, int series, int index) 1412 { 1413 final Pixels pix = getPixels(metaData, series); 1414 1415 if (pix != null) 1416 removeChannel(pix, index); 1417 } 1418 1419 /** 1420 * @deprecated Use {@link #removeChannel(OMEXMLMetadata, int, int)} instead 1421 */ 1422 @Deprecated 1423 public static void removeChannel(OMEXMLMetadataImpl metaData, int series, int index) 1424 { 1425 removeChannel((OMEXMLMetadata) metaData, series, index); 1426 } 1427 1428 /** 1429 * Remove a channel from the specified Pixels object. 1430 */ 1431 public static void removeChannel(Pixels pix, int index) 1432 { 1433 if (pix.sizeOfChannelList() > index) 1434 pix.removeChannel(pix.getChannel(index)); 1435 } 1436 1437 /** 1438 * Set the number of channel for the specified image series in metaData description.<br> 1439 * This is different from {@link #getSizeC(OMEXMLMetadata, int)}. 1440 */ 1441 public static void setNumChannel(OMEXMLMetadata metaData, int series, int num) 1442 { 1443 final OME ome = getOME(metaData); 1444 1445 ensureSeries(ome, series); 1446 1447 final Image img = ome.getImage(series); 1448 Pixels pix = img.getPixels(); 1449 1450 if (pix == null) 1451 { 1452 // create pixels object 1453 pix = new Pixels(); 1454 img.setPixels(pix); 1455 } 1456 1457 // keep only desired number of image 1458 while (pix.sizeOfChannelList() > num) 1459 removeChannel(pix, pix.sizeOfChannelList() - 1); 1460 1461 // create missing image 1462 ensureChannel(pix, num - 1); 1463 } 1464 1465 /** 1466 * @deprecated Use {@link #setNumChannel(OMEXMLMetadata, int, int)} instead 1467 */ 1468 @Deprecated 1469 public static void setNumChannel(OMEXMLMetadataImpl metaData, int series, int num) 1470 { 1471 setNumChannel((OMEXMLMetadata) metaData, series, num); 1472 } 1473 1474 /** 1475 * Initialize default channel name until specified index if they are missing from the meta data 1476 * description. 1477 */ 1478 private static void prepareMetaChannelName(OMEXMLMetadata metaData, int series, int channel) 1479 { 1480 int c = getNumChannel(metaData, series); 1481 1482 while (channel >= c) 1483 { 1484 // set default channel name 1485 metaData.setChannelName(getDefaultChannelName(c), series, c); 1486 c++; 1487 } 1488 } 1489 1490 /** 1491 * Returns name of specified channel image series. 1492 */ 1493 public static String getChannelName(OMEXMLMetadata metaData, int series, int channel) 1494 { 1495 // needed as LOCI does not initialize them on read 1496 prepareMetaChannelName(metaData, series, channel); 1497 1498 final String result = StringUtil.getValue(metaData.getChannelName(series, channel), 1499 getDefaultChannelName(channel)); 1500 final String cleaned = XMLUtil.filterString(result); 1501 1502 // cleaned string != original value --> set it 1503 if (!cleaned.equals(result)) 1504 setChannelName(metaData, series, channel, cleaned); 1505 1506 return cleaned; 1507 } 1508 1509 /** 1510 * @deprecated Use {@link #getChannelName(OMEXMLMetadata, int, int)} instead 1511 */ 1512 @Deprecated 1513 public static String getChannelName(OMEXMLMetadataImpl metaData, int series, int channel) 1514 { 1515 return getChannelName((OMEXMLMetadata) metaData, series, channel); 1516 } 1517 1518 /** 1519 * Set name of specified channel image series. 1520 */ 1521 public static void setChannelName(OMEXMLMetadata metaData, int series, int channel, String value) 1522 { 1523 // needed as LOCI only add current channel if it's missing 1524 prepareMetaChannelName(metaData, series, channel - 1); 1525 1526 metaData.setChannelName(value, series, channel); 1527 } 1528 1529 /** 1530 * @deprecated Use {@link #setChannelName(OMEXMLMetadata, int, int, String)} instead 1531 */ 1532 @Deprecated 1533 public static void setChannelName(OMEXMLMetadataImpl metaData, int series, int channel, String value) 1534 { 1535 setChannelName((OMEXMLMetadata) metaData, series, channel, value); 1536 } 1537 1538 /** 1539 * Returns Color of specified channel image series. 1540 */ 1541 public static Color getChannelColor(OMEXMLMetadata metaData, int series, int channel) 1542 { 1543 // needed as LOCI does not initialize them on read 1544 prepareMetaChannelName(metaData, series, channel); 1545 1546 return OMEUtil.getJavaColor(metaData.getChannelColor(series, channel)); 1547 } 1548 1549 /** 1550 * @deprecated Use {@link #getChannelColor(OMEXMLMetadata, int, int)} instead 1551 */ 1552 @Deprecated 1553 public static Color getChannelColor(OMEXMLMetadataImpl metaData, int series, int channel) 1554 { 1555 return getChannelColor((OMEXMLMetadata) metaData, series, channel); 1556 } 1557 1558 /** 1559 * Create and return a default (OME XML) Metadata object with default image name. 1560 */ 1561 public static OMEXMLMetadata createMetadata(String name) 1562 { 1563 final OMEXMLMetadata result = OMEUtil.createOMEXMLMetadata(); 1564 final OME ome = getOME(result); 1565 1566 ensureSeries(ome, 0); 1567 1568 result.setImageID(MetadataTools.createLSID("Image", 0), 0); 1569 result.setImageName(name, 0); 1570 1571 return result; 1572 } 1573 1574 /** 1575 * @deprecated Use {@link #createMetadata(String)} instead. 1576 */ 1577 @Deprecated 1578 public static OMEXMLMetadataImpl createDefaultMetadata(String name) 1579 { 1580 return (OMEXMLMetadataImpl) createMetadata(name); 1581 } 1582 1583 /** 1584 * @deprecated Use {@link OMEUtil#createOMEXMLMetadata(MetadataRetrieve, int)} 1585 */ 1586 @Deprecated 1587 public static OMEXMLMetadata createOMEMetadata(loci.formats.meta.MetadataRetrieve metadata, int series) 1588 { 1589 return OMEUtil.createOMEXMLMetadata(metadata, series); 1590 } 1591 1592 /** 1593 * Set metadata object with the given image properties. 1594 * 1595 * @param metadata 1596 * metadata object to fill. 1597 * @param sizeX 1598 * width in pixels (need to be >= 1) 1599 * @param sizeY 1600 * height in pixels (need to be >= 1) 1601 * @param sizeC 1602 * number of channel (need to be >= 1) 1603 * @param sizeZ 1604 * number of Z slices (need to be >= 1) 1605 * @param sizeT 1606 * number of T frames (need to be >= 1) 1607 * @param dataType 1608 * data type. 1609 * @param separateChannel 1610 * true if we want channel data to be separated. 1611 */ 1612 public static void setMetaData(OMEXMLMetadata metadata, int sizeX, int sizeY, int sizeC, int sizeZ, int sizeT, 1613 DataType dataType, boolean separateChannel) 1614 { 1615 OME ome = (OME) metadata.getRoot(); 1616 1617 if (ome == null) 1618 { 1619 metadata.createRoot(); 1620 ome = (OME) metadata.getRoot(); 1621 } 1622 1623 // keep only one image 1624 setNumSeries(metadata, 1); 1625 // clean TiffData metadata (can produce error on reloading) 1626 cleanTiffData(ome.getImage(0)); 1627 // clean binData metadata (can produce error on reloading) 1628 cleanBinData(ome.getImage(0)); 1629 1630 if (StringUtil.isEmpty(metadata.getImageID(0))) 1631 metadata.setImageID(MetadataTools.createLSID("Image", 0), 0); 1632 if (StringUtil.isEmpty(metadata.getImageName(0))) 1633 metadata.setImageName("Sample", 0); 1634 1635 if (StringUtil.isEmpty(metadata.getPixelsID(0))) 1636 metadata.setPixelsID(MetadataTools.createLSID("Pixels", 0), 0); 1637 1638 // prefer big endian as JVM is big endian 1639 metadata.setPixelsBigEndian(Boolean.TRUE, 0); 1640 metadata.setPixelsBinDataBigEndian(Boolean.TRUE, 0, 0); 1641 // force XYCZT dimension order 1642 metadata.setPixelsDimensionOrder(DimensionOrder.XYCZT, 0); 1643 1644 // adjust pixel type and dimension size 1645 metadata.setPixelsType(dataType.toPixelType(), 0); 1646 metadata.setPixelsSizeX(OMEUtil.getPositiveInteger(sizeX), 0); 1647 metadata.setPixelsSizeY(OMEUtil.getPositiveInteger(sizeY), 0); 1648 metadata.setPixelsSizeC(OMEUtil.getPositiveInteger(sizeC), 0); 1649 metadata.setPixelsSizeZ(OMEUtil.getPositiveInteger(sizeZ), 0); 1650 metadata.setPixelsSizeT(OMEUtil.getPositiveInteger(sizeT), 0); 1651 1652 // clean plane metadata outside allowed range 1653 cleanPlanes(ome.getImage(0)); 1654 1655 // get time interval information 1656 double timeInterval = MetaDataUtil.getTimeInterval(metadata, 0, 0d); 1657 // not defined ? 1658 if (timeInterval == 0d) 1659 { 1660 // try to compute it from time positions 1661 timeInterval = getTimeIntervalFromTimePositions(metadata, 0); 1662 // we got something --> set it as the time interval 1663 if (timeInterval != 0d) 1664 MetaDataUtil.setTimeInterval(metadata, 0, timeInterval); 1665 } 1666 1667 // fix channel number depending separate channel flag 1668 if (separateChannel) 1669 { 1670 // set channel number 1671 setNumChannel(metadata, 0, sizeC); 1672 1673 for (int c = 0; c < sizeC; c++) 1674 { 1675 if (StringUtil.isEmpty(metadata.getChannelID(0, c))) 1676 metadata.setChannelID(MetadataTools.createLSID("Channel", 0, c), 0, c); 1677 metadata.setChannelSamplesPerPixel(new PositiveInteger(Integer.valueOf(1)), 0, c); 1678 // metadata.getChannelName(0, c); 1679 } 1680 } 1681 else 1682 { 1683 // set channel number 1684 setNumChannel(metadata, 0, 1); 1685 1686 if (StringUtil.isEmpty(metadata.getChannelID(0, 0))) 1687 metadata.setChannelID(MetadataTools.createLSID("Channel", 0, 0), 0, 0); 1688 metadata.setChannelSamplesPerPixel(new PositiveInteger(Integer.valueOf(sizeC)), 0, 0); 1689 } 1690 } 1691 1692 /** 1693 * @deprecated Use {@link #setMetaData(OMEXMLMetadata, int, int, int, int, int, DataType, boolean)} instead 1694 */ 1695 @Deprecated 1696 public static void setMetaData(OMEXMLMetadataImpl metadata, int sizeX, int sizeY, int sizeC, int sizeZ, int sizeT, 1697 DataType dataType, boolean separateChannel) 1698 { 1699 setMetaData((OMEXMLMetadata) metadata, sizeX, sizeY, sizeC, sizeZ, sizeT, dataType, separateChannel); 1700 } 1701 1702 /** 1703 * Generates meta data for the given image properties. 1704 * 1705 * @param sizeX 1706 * width in pixels. 1707 * @param sizeY 1708 * height in pixels. 1709 * @param sizeC 1710 * number of channel. 1711 * @param sizeZ 1712 * number of Z slices. 1713 * @param sizeT 1714 * number of T frames. 1715 * @param dataType 1716 * data type. 1717 * @param separateChannel 1718 * true if we want channel data to be separated. 1719 * @return OMEXMLMetadata 1720 * @throws ServiceException 1721 */ 1722 public static OMEXMLMetadata generateMetaData(int sizeX, int sizeY, int sizeC, int sizeZ, int sizeT, 1723 DataType dataType, boolean separateChannel) throws ServiceException 1724 { 1725 final OMEXMLMetadata result = createMetadata("Sample"); 1726 1727 setMetaData(result, sizeX, sizeY, sizeC, sizeZ, sizeT, dataType, separateChannel); 1728 1729 return result; 1730 } 1731 1732 /** 1733 * Generates Meta Data for the given arguments. 1734 * 1735 * @see #setMetaData(OMEXMLMetadata, int, int, int, int, int, DataType, boolean) 1736 */ 1737 public static OMEXMLMetadata generateMetaData(int sizeX, int sizeY, int sizeC, DataType dataType, 1738 boolean separateChannel) throws ServiceException 1739 { 1740 return generateMetaData(sizeX, sizeY, sizeC, 1, 1, dataType, separateChannel); 1741 } 1742 1743 /** 1744 * Generates Meta Data for the given BufferedImage. 1745 * 1746 * @see #setMetaData(OMEXMLMetadata, int, int, int, int, int, DataType, boolean) 1747 */ 1748 public static OMEXMLMetadata generateMetaData(IcyBufferedImage image, boolean separateChannel) 1749 throws ServiceException 1750 { 1751 return generateMetaData(image.getSizeX(), image.getSizeY(), image.getSizeC(), image.getDataType_(), 1752 separateChannel); 1753 } 1754 1755 /** 1756 * @deprecated Use {@link #generateMetaData(Sequence, boolean)} instead. 1757 */ 1758 @Deprecated 1759 public static OMEXMLMetadata generateMetaData(Sequence sequence, boolean useZ, boolean useT, 1760 boolean separateChannel) 1761 { 1762 return generateMetaData(sequence, separateChannel); 1763 } 1764 1765 /** 1766 * @deprecated Use {@link #generateMetaData(Sequence, boolean)} instead. 1767 */ 1768 @Deprecated 1769 public static OMEXMLMetadata generateMetaData(Sequence sequence, int sizeZ, int sizeT, boolean separateChannel) 1770 { 1771 return generateMetaData(sequence, separateChannel); 1772 } 1773 1774 /** 1775 * Generates Meta Data for the given Sequence. 1776 * 1777 * @see #setMetaData(OMEXMLMetadata, int, int, int, int, int, DataType, boolean) 1778 */ 1779 public static OMEXMLMetadata generateMetaData(Sequence sequence, boolean separateChannel) 1780 { 1781 // do a copy as we mean use several time the same source sequence metadata 1782 final OMEXMLMetadata result = OMEUtil.createOMEXMLMetadata(sequence.getOMEXMLMetadata()); 1783 1784 setMetaData(result, sequence.getSizeX(), sequence.getSizeY(), sequence.getSizeC(), sequence.getSizeZ(), 1785 sequence.getSizeT(), sequence.getDataType_(), separateChannel); 1786 1787 return result; 1788 } 1789 1790 /** 1791 * Keep only the specified image series. 1792 */ 1793 public static void keepSingleSerie(OMEXMLMetadata metaData, int num) 1794 { 1795 final OME ome = getOME(metaData); 1796 final int numSeries = ome.sizeOfImageList(); 1797 final Image img = getSeries(metaData, num); 1798 1799 // nothing to do 1800 if (img == null) 1801 return; 1802 1803 // keep only the desired image 1804 for (int i = numSeries - 1; i >= 0; i--) 1805 if (i != num) 1806 ome.removeImage(ome.getImage(i)); 1807 1808 final Set<Object> toKeep = new HashSet<Object>(); 1809 1810 // try to keep associated dataset only 1811 toKeep.clear(); 1812 for (int i = 0; i < img.sizeOfLinkedDatasetList(); i++) 1813 toKeep.add(img.getLinkedDataset(i)); 1814 if (!toKeep.isEmpty()) 1815 { 1816 for (int i = ome.sizeOfDatasetList() - 1; i >= 0; i--) 1817 { 1818 final Dataset obj = ome.getDataset(i); 1819 if (!toKeep.contains(obj)) 1820 ome.removeDataset(obj); 1821 } 1822 } 1823 // just assume they are indirectly linked 1824 else if (ome.sizeOfDatasetList() == numSeries) 1825 { 1826 for (int i = numSeries - 1; i >= 0; i--) 1827 if (i != num) 1828 ome.removeDataset(ome.getDataset(i)); 1829 } 1830 1831 // try to keep associated ROI only 1832 toKeep.clear(); 1833 for (int i = 0; i < img.sizeOfLinkedROIList(); i++) 1834 toKeep.add(img.getLinkedROI(i)); 1835 if (!toKeep.isEmpty()) 1836 { 1837 for (int i = ome.sizeOfROIList() - 1; i >= 0; i--) 1838 { 1839 final ROI obj = ome.getROI(i); 1840 if (!toKeep.contains(obj)) 1841 ome.removeROI(obj); 1842 } 1843 } 1844 // just assume they are indirectly linked 1845 else if (ome.sizeOfROIList() == numSeries) 1846 { 1847 for (int i = numSeries - 1; i >= 0; i--) 1848 if (i != num) 1849 ome.removeROI(ome.getROI(i)); 1850 } 1851 1852 // try to keep associated experiment only 1853 final Experiment exp = img.getLinkedExperiment(); 1854 if (exp != null) 1855 { 1856 for (int i = ome.sizeOfExperimentList() - 1; i >= 0; i--) 1857 { 1858 final Experiment obj = ome.getExperiment(i); 1859 if (obj != exp) 1860 ome.removeExperiment(obj); 1861 } 1862 } 1863 else if (ome.sizeOfExperimentList() == numSeries) 1864 { 1865 for (int i = numSeries - 1; i >= 0; i--) 1866 if (i != num) 1867 ome.removeExperiment(ome.getExperiment(i)); 1868 } 1869 1870 // try to keep associated experimenter only 1871 final Experimenter expr = img.getLinkedExperimenter(); 1872 if (expr != null) 1873 { 1874 for (int i = ome.sizeOfExperimenterList() - 1; i >= 0; i--) 1875 { 1876 final Experimenter obj = ome.getExperimenter(i); 1877 if (obj != expr) 1878 ome.removeExperimenter(obj); 1879 } 1880 } 1881 else if (ome.sizeOfExperimenterList() == numSeries) 1882 { 1883 for (int i = numSeries - 1; i >= 0; i--) 1884 if (i != num) 1885 ome.removeExperimenter(ome.getExperimenter(i)); 1886 } 1887 1888 // try to keep associated experimenter group only 1889 final ExperimenterGroup exprGroup = img.getLinkedExperimenterGroup(); 1890 if (exprGroup != null) 1891 { 1892 for (int i = ome.sizeOfExperimenterGroupList() - 1; i >= 0; i--) 1893 { 1894 final ExperimenterGroup obj = ome.getExperimenterGroup(i); 1895 if (obj != exprGroup) 1896 ome.removeExperimenterGroup(obj); 1897 } 1898 } 1899 else if (ome.sizeOfExperimenterGroupList() == numSeries) 1900 { 1901 for (int i = numSeries - 1; i >= 0; i--) 1902 if (i != num) 1903 ome.removeExperimenterGroup(ome.getExperimenterGroup(i)); 1904 } 1905 1906 // try to keep associated instrument only 1907 final Instrument instr = img.getLinkedInstrument(); 1908 if (instr != null) 1909 { 1910 for (int i = ome.sizeOfInstrumentList() - 1; i >= 0; i--) 1911 { 1912 final Instrument obj = ome.getInstrument(i); 1913 if (obj != instr) 1914 ome.removeInstrument(obj); 1915 } 1916 } 1917 else if (ome.sizeOfInstrumentList() == numSeries) 1918 { 1919 for (int i = numSeries - 1; i >= 0; i--) 1920 if (i != num) 1921 ome.removeInstrument(ome.getInstrument(i)); 1922 } 1923 1924 // others misc data to clean 1925 if (ome.sizeOfPlateList() == numSeries) 1926 { 1927 for (int i = numSeries - 1; i >= 0; i--) 1928 if (i != num) 1929 ome.removePlate(ome.getPlate(i)); 1930 } 1931 if (ome.sizeOfProjectList() == numSeries) 1932 { 1933 for (int i = numSeries - 1; i >= 0; i--) 1934 if (i != num) 1935 ome.removeProject(ome.getProject(i)); 1936 } 1937 if (ome.sizeOfScreenList() == numSeries) 1938 { 1939 for (int i = numSeries - 1; i >= 0; i--) 1940 if (i != num) 1941 ome.removeScreen(ome.getScreen(i)); 1942 } 1943 } 1944 1945 /** 1946 * Keep only the specified plane metadata. 1947 */ 1948 public static void keepSinglePlane(Image img, int index) 1949 { 1950 final Pixels pix = img.getPixels(); 1951 if (pix == null) 1952 return; 1953 1954 final int numPlane = pix.sizeOfPlaneList(); 1955 final Plane plane = getPlane(pix, index); 1956 1957 // keep only the desired plane 1958 for (int i = numPlane - 1; i >= 0; i--) 1959 { 1960 if (i != index) 1961 pix.removePlane(pix.getPlane(i)); 1962 } 1963 1964 final Set<Object> toKeep = new HashSet<Object>(); 1965 1966 // try to keep associated annotation only 1967 toKeep.clear(); 1968 for (int i = 0; i < plane.sizeOfLinkedAnnotationList(); i++) 1969 toKeep.add(plane.getLinkedAnnotation(i)); 1970 if (!toKeep.isEmpty()) 1971 { 1972 for (int i = img.sizeOfLinkedAnnotationList() - 1; i >= 0; i--) 1973 { 1974 final Annotation obj = img.getLinkedAnnotation(i); 1975 if (!toKeep.contains(obj)) 1976 img.unlinkAnnotation(obj); 1977 } 1978 } 1979 // just assume they are indirectly linked 1980 else if (img.sizeOfLinkedAnnotationList() == numPlane) 1981 { 1982 for (int i = numPlane - 1; i >= 0; i--) 1983 if (i != index) 1984 img.unlinkAnnotation(img.getLinkedAnnotation(i)); 1985 } 1986 1987 // clean some data 1988 if (pix.sizeOfBinDataList() == numPlane) 1989 { 1990 for (int i = numPlane - 1; i >= 0; i--) 1991 if (i != index) 1992 pix.removeBinData(pix.getBinData(i)); 1993 } 1994 if (pix.sizeOfTiffDataList() == numPlane) 1995 { 1996 for (int i = numPlane - 1; i >= 0; i--) 1997 if (i != index) 1998 pix.removeTiffData(pix.getTiffData(i)); 1999 } 2000 } 2001 2002 /** 2003 * @deprecated Use {@link #keepSingleSerie(OMEXMLMetadata, int)} instead 2004 */ 2005 @Deprecated 2006 public static void keepSingleSerie(OMEXMLMetadataImpl metaData, int num) 2007 { 2008 keepSingleSerie((OMEXMLMetadata) metaData, num); 2009 } 2010 2011 /** 2012 * Keep only plane(s) at specified C, Z, T position from the given metadata. 2013 * 2014 * @param img 2015 * image metadata to clean plane from 2016 * @param posT 2017 * keep Plane at given T position (-1 to keep all) 2018 * @param posZ 2019 * keep Plane at given Z position (-1 to keep all) 2020 * @param posC 2021 * keep Plane at given C position (-1 to keep all) 2022 */ 2023 public static void keepPlanes(Image img, int posT, int posZ, int posC) 2024 { 2025 final Pixels pix = img.getPixels(); 2026 if (pix == null) 2027 return; 2028 2029 final int sizeT = OMEUtil.getValue(pix.getSizeT(), 0); 2030 final int sizeZ = OMEUtil.getValue(pix.getSizeZ(), 0); 2031 final int sizeC = OMEUtil.getValue(pix.getSizeC(), 0); 2032 2033 for (int t = 0; t < sizeT; t++) 2034 { 2035 final boolean removeT = (posT != -1) && (posT != t); 2036 2037 for (int z = 0; z < sizeZ; z++) 2038 { 2039 final boolean removeZ = (posZ != -1) && (posZ != z); 2040 2041 for (int c = 0; c < sizeC; c++) 2042 { 2043 final boolean removeC = (posC != -1) && (posC != c); 2044 2045 if (removeT || removeZ || removeC) 2046 removePlane(img, t, z, c); 2047 } 2048 } 2049 } 2050 } 2051 2052 /** 2053 * Keep only plane(s) at specified C, Z, T position from the given metadata. 2054 * 2055 * @param posT 2056 * keep Plane at given T position (-1 to keep all) 2057 * @param posZ 2058 * keep Plane at given Z position (-1 to keep all) 2059 * @param posC 2060 * keep Plane at given C position (-1 to keep all) 2061 */ 2062 public static void keepPlanes(OMEXMLMetadata metadata, int series, int posT, int posZ, int posC) 2063 { 2064 final Image img = getSeries(metadata, series); 2065 2066 if (img != null) 2067 keepPlanes(img, posT, posZ, posC); 2068 } 2069 2070 /** 2071 * Clean plane(s) which are outside the pixel sizeC / sizeZ and sizeT. 2072 * 2073 * @param img 2074 * image metadata to clean plane from 2075 */ 2076 public static void cleanPlanes(Image img) 2077 { 2078 final Pixels pix = img.getPixels(); 2079 if (pix == null) 2080 return; 2081 2082 final int sizeT = OMEUtil.getValue(pix.getSizeT(), 0); 2083 final int sizeZ = OMEUtil.getValue(pix.getSizeZ(), 0); 2084 final int sizeC = OMEUtil.getValue(pix.getSizeC(), 0); 2085 if ((sizeT < 1) || (sizeZ < 1) || (sizeC < 1)) 2086 return; 2087 2088 // get allowed maximum plane 2089 final int allowedMaxPlaneIndex = getPlaneIndex(pix, sizeT - 1, sizeZ - 1, sizeC - 1); 2090 // current number of plane 2091 int maxPlaneIndex = pix.sizeOfPlaneList() - 1; 2092 2093 // remove plan outside allowed region 2094 while (maxPlaneIndex > allowedMaxPlaneIndex) 2095 removePlane(img, maxPlaneIndex--); 2096 } 2097 2098 /** 2099 * Clean TiffData packet 2100 * 2101 * @param img 2102 * image metadata to clean TiffData from 2103 */ 2104 public static void cleanTiffData(Image img) 2105 { 2106 final Pixels pix = img.getPixels(); 2107 if (pix == null) 2108 return; 2109 2110 while (pix.sizeOfTiffDataList() > 0) 2111 pix.removeTiffData(pix.getTiffData(pix.sizeOfTiffDataList() - 1)); 2112 } 2113 2114 /** 2115 * Clean BinData packet 2116 * 2117 * @param img 2118 * image metadata to clean BinData from 2119 */ 2120 public static void cleanBinData(Image img) 2121 { 2122 final Pixels pix = img.getPixels(); 2123 if (pix == null) 2124 return; 2125 2126 while (pix.sizeOfBinDataList() > 0) 2127 pix.removeBinData(pix.getBinData(pix.sizeOfBinDataList() - 1)); 2128 } 2129 2130 /** 2131 * Cleanup the meta data (sometime we have empty data structure sitting there) 2132 */ 2133 public static void clean(OMEXMLMetadata metaData) 2134 { 2135 final OME ome = getOME(metaData); 2136 final StructuredAnnotations annotations = ome.getStructuredAnnotations(); 2137 2138 if (annotations != null) 2139 { 2140 for (int i = annotations.sizeOfXMLAnnotationList() - 1; i >= 0; i--) 2141 { 2142 final XMLAnnotation xmlAnnotation = annotations.getXMLAnnotation(i); 2143 2144 if (isEmpty(xmlAnnotation)) 2145 annotations.removeXMLAnnotation(xmlAnnotation); 2146 } 2147 } 2148 } 2149 2150 /** 2151 * @deprecated Use {@link #clean(OMEXMLMetadata)} instead. 2152 */ 2153 @Deprecated 2154 public static void clean(OMEXMLMetadataImpl metaData) 2155 { 2156 clean((OMEXMLMetadata) metaData); 2157 } 2158 2159 /** 2160 * Returns <code>true</code> if the specified XML annotation are empty. 2161 */ 2162 public static boolean isEmpty(XMLAnnotation xmlAnnotation) 2163 { 2164 return StringUtil.isEmpty(xmlAnnotation.getDescription()) && StringUtil.isEmpty(xmlAnnotation.getValue()); 2165 } 2166}