Erosion/Dilatation in C++



  • Hallo,
    Ich soll zunächst einmal die Erosion implementieren, dabei ist das folgende Grundgerüst gegeben, lade nur die hauptdatei hier hoch:

    #include <iostream>
    #include <stdio.h>
    #include <limits>
    #include "ErosionFilter.h"
    
    /* Constructor. */
    ErosionFilter::ErosionFilter()
    {
      // Set structure element to NULL.
      m_StructureElement = NULL;
    }
    
    /* Destructor. */
    ErosionFilter::~ErosionFilter()
    {
      // Nothing to do here.
    }
    
    /* Set the structure element for the filter. */
    void ErosionFilter::SetStructureElement(  StructureElement* structureElement )
    {
      m_StructureElement = structureElement;
    }
    
    /* Execute the Erosion filter. */
    bool ErosionFilter::Execute()
    {
      // Check if structure element is set.
      if( m_StructureElement == NULL )
      {
        std::cout << "Error: No structure element set!" << std::endl;
        return false;
      }
    
      // First, create a valid output image.
      // This fails, if no valid input image is available.
      if( !CreateOutputImage() )
      {
        return false;
      }
    
      /*
       * TODO: Aufgabe 3a: Vervollstaendigen Sie die Implementierung der Klasse
       * ErosionFilter.
       *
       * Implementieren Sie die Dilatation dabei so, dass der Operator sowohl auf
       * Grauwertbildern (entsprechend dem in der Vorlesung eingefuehrten Maximumoperator)
       * als auch auf Binaerbildern (im Sinne der entsprechenden Mengenoperation)
       * durchfuehrbar ist. Fuer die genaue Definition des Filters beachten Sie das
       * Aufgabenblatt und die Folien zur Uebung und Vorlesung.
       *
       * Die Schleifen zur Iteration ueber die Bildpixel und die Nachbarschaften,
       * sowie die Ueberpruefung der Randbedingungen sind bereits vorgegeben.
       *
       * Hinweis: C++ definiert innerhalb der std-Umgebung die Funktionen
       *                          std::numeric_limits<TYPE>::min()
       *            und           std::numeric_limits<TYPE>::max()
       * um das Minimum/Maximum fuer einen der Standard-Typen (unsigned char, char,
       * short, int float etc.) zu bestimmen.
       *
       * Die Syntax sieht zwar etwas kompliziert aus, in den eckigen Klammern wird
       * einfach der Typ uebergeben (als template-Argument):
       *   std::numeric_limits<float>::max()
       * liefert dementsprechend den groessten moeglichen float-Wert zurueck. Da der
       * von uns definierte PixelType einer dieser Stabdardtypen ist , koennen Sie
       * folgenden Aufruf verwenden, um Variablen mit dem Minimum/Maximum des Types
       * zu initialisieren:
       *   Image::PixelType min = std::numeric_limits<Image::PixelType>::min();
       *   Image::PixelType max = std::numeric_limits<Image::PixelType>::max();
       * Alternativ gehen sie einfachd avon aus, dass Image::PixelType als short
       * definiert ist und verwenden sie 32767 als Maximum und -32768 als Minimum.
       */
    
      // We define few constants required for the filtering. It is more efficient to
      // use constants instead of calling the member functions in each iteration.
      const int kernelHalfSizeX = m_StructureElement->GetHalfSizeX();
      const int kernelHalfSizeY = m_StructureElement->GetHalfSizeY();
    
      // We cast the size to integer to avoid signed/unsigned warnings in the boundary checking.
      const int imageSizeX = static_cast<int> ( m_InputImage->GetSizeX() );
      const int imageSizeY = static_cast<int> ( m_InputImage->GetSizeY() );
    
      Image::PixelType min = 0;
      Image::PixelType max = std::numeric_limits<Image::PixelType>::max();
    
      // Iterate over all pixel coordinates.
      for( int y = 0; y < 0; y++ )
      {
        for( int x = 0; x < 1; x++ )
        {
          // Die Koordinaten des aktuellen Pixels sind jetzt gegeben als (x,y).
    
          // Iterate over all neighborhood pixel coordinates.
          for( int m = -kernelHalfSizeY; m <= kernelHalfSizeY; m++ )
          {
            // Compute the pixel y coordinate for this kernel row.
            int j = y + m;
    
            // Apply reflected boundary conditions if coordinate is outside the image.
            if( j < 0 )
            {
              j = -j - 1;
            }
            else if( j >= imageSizeY )
            {
              j = 2 * imageSizeY - j - 1;
            }
    
            for( int k = -kernelHalfSizeX; k <= kernelHalfSizeX; k++ )
            {
              // Compute the pixel x coordinate for this kernel column.
              int i = x + k;
    
              // Apply reflected boundary conditions if coordinate is outside the image.
              if( i < 0 )
              {
                i = -i - 1;
              }
              else if( i >= imageSizeX )
              {
                i = 2 * imageSizeX - i - 1;
              }
    
              // Die Koordinaten des Punktes in der Nachbarschaft des aktuellen Pixels (x,y)
              // sind jetzt gegeben als (i,j).
              // Die korrespondierende Position in der Maske ist (k,m).
              // Beachten Sie, dass auf die Koordinaten (i,j) schon die Randbedingungen
              // angewendet wurden.
              min = m_InputImage->GetPixel(i,j)>m_InputImage->GetPixel(x,y)?min:m_InputImage->GetPixel(i,j);
    
              printf("Min: %d\n", min);
    
            }
          }
          // Sie muessen die Grauwerte des Ausgabebildes setzen.
          //für grauwert bilder verwende min
    
          //für binär verwende logisches UND zur abfrage ob in menge enthalten
          //printf("min: %d\n", min);
          m_OutputImage->SetPixel(x,y,min);
        }
      }
    
      return true;
    }
    

    So das ganze funktioniert leider nicht, habe das minimum ermitteln wollen in der nachbarschaft, beim binären bildern sollen wir das mit logischen AND und der prüfung ob es in der menge ist machen, bei grauwertbildern mit dem minimumoperator.



  • Was funktioniert nicht? Was erwartest du und was passiert stattdessen? Kannst du so viel posten, dass man das Problem nachstellen kann?: http://www.c-plusplus.net/forum/304133



  • Was funktioniert nicht? Hättest vielleicht noch im Titel dazu schreiben können, dass es um Bildbearbeitung geht. Wollt zuerst gar nicht reinschauen, weil ich dachte, es geht um Erderosion oder so.

    Der Code ist nicht von dir, oder? Mich stören etwas die ganzen sinnlosen Kommentare, wie /* Constructor. */. Nee, oder?



  • ne der code ist von unserem übungsleiter, nur der untere teil ist von mir. Es soll zu verkleinern der struckturen kommen bei einem bild. ich krieg aber nur ein schwarzes ausgabebild, hier noch mal die theorie zur erosion: I-E, heisst minkowskisubtraktion. Es enstpricht einer minimierungsfunktion, d.h es soll in der nachbarschaft der maske das kleinste element genommen werden und statt des aktuellen pixels gesetzt werden.



  • Hier wird nicht soooo viel iteriert

    for( int y = 0; y < 0; y++ )
    

    😉



  • Hier auch nicht:

    for( int x = 0; x < 1; x++ )
    


  • ach mist stimmt danke hatte das zu test zwecken kleiner gestellt, aber jetzt kommt das bild zwar wieder aber daran erodiert ist immer noch nichts.



  • wie einige schon geschrieben haben, fehlt Information um zu prüfen, was nicht funktioniert. Erst mal solltest Du uns die von Dir gewählte Erosions-/Dilatationsmaske zeigen. Prinzipiell ist es so, dass das Center-Pixel gesetzt wird, wenn bei den gesetzten Maskenpixeln die Bildpixel ebenfalls gesetzt sind, und sonst nicht.

    Z.B. ohne Betrachtung der Ränder (keine schöne Lösung)

    for (int y = 0; y < image.rows()-kernel.rows(); y++)
    {
        for (int x = 1; x < image.columns()-kernel.columns(); x++)
        {
             image[y][x] = erodePixel(y, x, kernel, image); // kernel ist eine 3x3 maske
        }
    }
    
    // ...
    
    pixelVal erodePixel(int row, int col, Mask& kernel, Image& img)
    {
        bool result = false;
        for (int i = 0; i<kernel.rows(); ++i)
        {
            for (int j = 0; j<kernel.columns(); ++j)
            {
               result &= img[row+i][col+j] && kernel[i][j];
            }
        }
    
        return result;
    }
    


  • das sind die restlichen klassen:

    #include <iostream>
    #include "StructureElement.h"
    
    /* Constructor creates an 2*hX+1 x 2*hY+1 StructureElement with all elements
     * set to false except the center.
     * GetHalfSizeX() and GetHalfSizeY() will return hX, hY.
     * GetSizeX() and GetSizeY() will return 2*hX+1 and 2*hY+1. */
    StructureElement::StructureElement( unsigned int hX, unsigned int hY )
    {
      // Set half of height and width as member variables.
      m_HalfSizeX = hX;
      m_HalfSizeY = hY;
    
      // Compute size of the coefficient array.
      unsigned int sizeX = m_HalfSizeX * 2 + 1;
      unsigned int sizeY = m_HalfSizeY * 2 + 1;
      unsigned int arraySize = sizeX * sizeY;
    
      // Allocate elements bool array.
      m_Elements = new bool[arraySize];
    
      // Fill array with false.
      for( unsigned int i = 0; i < arraySize; i++ )
      {
        m_Elements[i] = false;
      }
      // Set center to true.
      SetInside( 0, 0, true );
    }
    
    /* Destructor to delete the array with coefficients. */
    StructureElement::~StructureElement()
    {
      delete[] m_Elements;
    }
    
    /* Get the StructureElement half-size for easy iteration over the mask. */
    int StructureElement::GetHalfSizeX() const
    {
      return m_HalfSizeX;
    }
    
    /* Get the StructureElement half-size for easy iteration over the mask. */
    int StructureElement::GetHalfSizeY() const
    {
      return m_HalfSizeY;
    }
    
    /* Compute and get the StructureElement size. */
    unsigned int StructureElement::GetSizeX() const
    {
      return 2 * m_HalfSizeX + 1;
    }
    
    /* Compute and get the StructureElement size. */
    unsigned int StructureElement::GetSizeY() const
    {
      return 2 * m_HalfSizeY + 1;
    }
    
    /* Returns true if the position (i,j) is part of the StructureElement,
     * else returns false.
     * StructureElement positions are indexed by -halfsize ... +halfsize */
    bool StructureElement::IsInside( int i, int j ) const
    {
      // Compute the correct position in the array.
      int index = i + GetHalfSizeX() + (j + GetHalfSizeY()) * GetSizeX();
    
      // Check if you are outside the mask.
      if( index < 0 || index >= static_cast<int> ( GetSizeX() * GetSizeY() ) )
      {
        std::cout << "Warning in StructureElement::IsInside(): index outside kernel mask!";
        return 0;
      }
    
      // Return the element value.
      return m_Elements[index];
    }
    
    /* Set the value of the StructureElement at position (i,j).
     * StructureElement positions are indexed by -halfsize ... +halfsize */
    void StructureElement::SetInside( int i, int j, bool value )
    {
      // Compute the correct position in the array.
      int index = i + GetHalfSizeX() + (j + GetHalfSizeY()) * GetSizeX();
    
      // Check if you are outside the mask.
      if( index < 0 || index >= static_cast<int> ( GetSizeX() * GetSizeY() ) )
      {
        std::cout << "Warning in StructureElement::SetCoefficient(): index outside kernel mask!";
        return;
      }
      // Set the element value.
      m_Elements[index] = value;
    }
    
    #include <iostream>
    #include "SquareStructureElement.h"
    
    /* Constructor creates a squared structure element of size
     * (2 * halfSize + 1) x (2 * halfSize + 1)
     * GetHalfSizeX() and GetHalfSizeY() will return halfSize.
     * GetSizeX() and GetSizeY() will return 2 * halfSize + 1. */
    SquareStructureElement::SquareStructureElement( unsigned int halfSize ) :
      StructureElement( halfSize, halfSize )
    {
      // The constructor of the base class is called to create a structure
      // element with the correct size.
    
      // All entries inside the structure kernel are now set to TRUE.
      for( int i = -GetHalfSizeX(); i <= GetHalfSizeX(); i++ )
        for( int j = -GetHalfSizeY(); j <= GetHalfSizeY(); j++ )
        {
          SetInside( i, j, true );
        }
    }
    
    #include "Image.h"   // Include the header file.
    #include <iostream>  // Include for printing text to the screen.
    #include <fstream>   // Include for reading and writing files.
    #include <string.h>  // Include for string handling.
    #include <vector>    // Include for vector handling.
    
    /* Constructor of an image. Creates an image of zero size without
     * allocating the image buffer.*/
    Image::Image()
    {
      // Create an empty image with zero-size.
      m_SizeX = 0;
      m_SizeY = 0;
    
      m_SpacingX = 1.0;
      m_SpacingY = 1.0;
    
      m_ImageBuffer = NULL;
    }
    
    /* Constructor of an image. Using this constructor an image of
     * the given size filled with zero-values is created. */
    Image::Image( const unsigned int x, const unsigned int y )
    {
      m_SizeX = x;
      m_SizeY = y;
    
      m_SpacingX = 1.0;
      m_SpacingY = 1.0;
    
      unsigned int size = m_SizeX * m_SizeY;
    
      if( size > 0 )
      {
        // Allocate the image buffer.
        m_ImageBuffer = new PixelType[size];
    
        // Initialize with zero values.
        memset( m_ImageBuffer, 0, size * sizeof(PixelType) );
    
        // Allocate a new reference counter for this image buffer and set to 1.
      }
      else
      {
        // If this is a zero-size image, do not allocate.
        m_ImageBuffer = NULL;
      }
    }
    
    // Destructor
    Image::~Image()
    {
      // free allocated memory
      ReleaseData();
    }
    
    /* Calculate a linearized index from the pixel coordinate (x, y). */
    unsigned int Image::GetIndexFromCoordinate( const unsigned int x, const unsigned int y ) const
    {
      return x + y * m_SizeX;
    }
    
    /* Get the value of the pixel at coordinate (x, y). The coordinates will be
     * converted into an linearized index internally. */
    Image::PixelType Image::GetPixel( const unsigned int x, const unsigned int y ) const
    {
      // Get linearized index from pixel coordinate.
      const unsigned int index = GetIndexFromCoordinate( x, y );
    
      return GetPixel( index );
    }
    
    /* Get the value of the pixel at index i. */
    Image::PixelType Image::GetPixel( const unsigned int i ) const
    {
      // Test if in bounds.
      if( i >= m_SizeX * m_SizeY )
      {
        return 0;
      }
    
      return m_ImageBuffer[i];
    }
    
    /* Set the value of the pixel at coordinate (x, y). The coordinates will be
     * converted into an linearized index internally.
     *
     * Returns success of the operation. */
    bool Image::SetPixel( const unsigned int x, const unsigned int y, const PixelType value )
    {
      // Get linearized index from pixel coordinate.
      const unsigned int index = GetIndexFromCoordinate( x, y );
    
      return SetPixel( index, value );
    }
    
    /* Set the value of the pixel at index i.
     *
     * Returns success of the operation. */
    bool Image::SetPixel( const unsigned int i, const PixelType value )
    {
      // Test if in bounds.
      if( i >= m_SizeX * m_SizeY )
      {
        return false;
      }
    
      m_ImageBuffer[i] = value;
    
      return true;
    }
    
    /* Set the spacing of the image. */
    void Image::SetSpacing( const double sx, const double sy )
    {
      m_SpacingX = sx;
      m_SpacingY = sy;
    }
    
    void Image::Print()
    {
      std::cout << "Image: [" << m_SizeX << "x" << m_SizeY << "] (" << m_SpacingX << "," << m_SpacingY << ")\n";
    }
    
    // Create this as an empty image of the given size.
    bool Image::Allocate( const unsigned int x, const unsigned int y )
    {
      ReleaseData();
    
      m_SizeX = x;
      m_SizeY = y;
    
      unsigned int size = m_SizeX * m_SizeY;
    
      if( size > 0 )
      {
        // Allocate the image buffer.
        m_ImageBuffer = new PixelType[size];
    
        // Initialize with zero values.
        memset( m_ImageBuffer, 0, size * sizeof(PixelType) );
      }
      else
      {
        // If this is a zero-size image, do not allocate.
        m_ImageBuffer = NULL;
    
        return false;
      }
    
      return true;
    }
    
    // Makes a new copy of this image.
    bool Image::CloneImage( const Image* other )
    {
      // Check if other image is NULL.
      if( other == NULL )
      {
        std::cout << "Error: Could not copy from NULL pointer!" << std::endl;
        return false;
      }
    
      // Check if images are the same.
      if( this == other )
      {
        return true;
      }
    
      // Check if reallocation is required.
      unsigned int otherSizeX = other->GetSizeX();
      unsigned int otherSizeY = other->GetSizeY();
      if( m_SizeX != otherSizeX || m_SizeY != otherSizeY )
      {
        this->Allocate( otherSizeX, otherSizeY );
      }
    
      // Check if spacing has to be changed.
      if( m_SpacingX != other->GetSpacingX() || m_SpacingY != other->GetSpacingY() )
      {
        this->SetSpacing( other->GetSpacingX(), other->GetSpacingY() );
      }
    
      // Copy buffer.
      const unsigned int size = m_SizeX * m_SizeY;
      for( unsigned int i = 0; i < size; ++i )
      {
        this->SetPixel( i, other->GetPixel( i ) );
      }
    
      // Return success.
      return true;
    }
    
    /* This method release the data of the image buffer (free memory) */
    void Image::ReleaseData()
    {
      // check if image buffer is allocated
       if ( m_ImageBuffer != NULL )
       {
         // free memory of image buffer
         delete [] m_ImageBuffer;
         m_ImageBuffer = NULL;
       }
    }
    
    #include <math.h>
    #include <iostream>
    
    #include "ImageFilter.h"
    
    /* Constructor of an filter. */
    ImageFilter::ImageFilter()
    {
      // Set image pointer to null.
      m_InputImage = NULL;
      m_OutputImage = NULL;
    }
    
    ImageFilter::~ImageFilter()
    {
      // Delete output image.
      if( m_OutputImage != NULL )
      {
        delete m_OutputImage;
      }
    }
    
    /* Set the input image to filter.
     * You have to set an input image before calling Execute(). */
    void ImageFilter::SetInputImage( Image* inputImage )
    {
      // set the input image
      m_InputImage = inputImage;
    }
    
    /* Get the filtered image.
     * You have to call this function after calling Execute(). */
    Image* ImageFilter::GetOutputImage()
    {
      // return the output image
      return m_OutputImage;
    }
    
    /* Creates the output image with same size as the input image. Usually this
     * function is called from Execute() before performing the filtering. */
    bool ImageFilter::CreateOutputImage()
    {
      // Check if a valid input image is set.
      if( m_InputImage == NULL )
      {
        std::cout << "Error: Cannot create output image! First set input image.";
        return false;
      }
    
      // Check, if output image is instantiated.
      if( m_OutputImage == NULL )
      {
        m_OutputImage = new Image();
      }
    
      // Avoid reallocation if output image is already created
      // and has the same size as the input image.
      if( ! (m_OutputImage->IsAllocated() && this->CheckImageDimensions( m_OutputImage, m_InputImage )) )
      {
        m_OutputImage->Allocate( m_InputImage->GetSizeX(), m_InputImage->GetSizeY() );
      }
    
      // Set image spacing.
      if( !this->CheckImageSpacing( m_OutputImage, m_InputImage ) )
      {
        m_OutputImage->SetSpacing( m_InputImage->GetSpacingX(), m_InputImage->GetSpacingY() );
      }
    
      return true;
    }
    
    /* Returns true, if both images have the same size. */
    bool ImageFilter::CheckImageDimensions( const Image* image1, const Image* image2 )
    {
      return (image1->GetSizeX() == image2->GetSizeX()
          && image1->GetSizeY() == image2->GetSizeY());
    }
    
    /* Returns true, if both images have the same spacing. */
    bool ImageFilter::CheckImageSpacing( const Image* image1, const Image* image2 )
    {
      // Spacing are float values -> define an epsilon to check if equal.
      const double epsilon = 0.000001;
    
      return (fabs( image1->GetSpacingX() - image2->GetSpacingX() ) < epsilon
          && fabs( image1->GetSpacingY() - image2->GetSpacingY() ) < epsilon);
    }
    
    #include "ImageIO.h"   // Include the header file.
    #include <iostream>    // Include for printing text to the screen.
    #include <fstream>     // Include for reading and writing files.
    ImageIO::ImageIO()
    {
    }
    
    ImageIO::~ImageIO()
    {
    }
    
    //
    // Read()
    //
    bool ImageIO::Read( const char* filename, Image* image )
    {
      if( CheckFilename( filename, "pgm" ) )
      {
        return ReadPGMImage( filename, image );
      }
      else if( CheckFilename( filename, "mha" ) || CheckFilename( filename, "mhd" ) )
      {
        return ReadMetaImage( filename, image );
      }
      else
      {
        std::cout << "ERROR: file extension unknown!\n";
        return false;
      }
    }
    
    //
    // Write()
    //
    bool ImageIO::Write( const char* filename, const Image* image )
    {
      if( !image )
      {
        std::cout << "ERROR: can not save empty image !\n";
        return false;
      }
    
      if( CheckFilename( filename, ".pgm" ) )
      {
        return WritePGMImage( filename, image );
      }
      else if( CheckFilename( filename, ".mha" ) || CheckFilename( filename, ".mhd" ) )
      {
        return WriteMetaImage( filename, image );
      }
      else
      {
        std::cout << "ERROR: file extension unknown!\n";
        return false;
      }
    }
    
    //
    // CheckFilename()
    //
    bool ImageIO::CheckFilename( const char* filename, const char* extension )
    {
      // String for making a few checks.
      std::string fnString = filename;
    
      // Return error if file name is empty.
      if( fnString == "" )
      {
        std::cout << "Error: Filename is empty!" << std::endl;
        return false;
      }
    
      // Test if the last 3 characters are the extension.
      std::string::size_type position = fnString.rfind( extension );
      if( position == std::string::npos && position != fnString.length() - 4 )
      {
        return false;
      }
    
      return true;
    }
    
    //
    // ReadPGMImage()
    //
    bool ImageIO::ReadPGMImage( const char* filename, Image* image )
    {
      // Variables for image size and gray value range
      unsigned int width;
      unsigned int height;
      unsigned int maxValue;
    
      // Variable to read header Note: it does not Stores it
      char header[100] = { '\n' };
      char *ptr = NULL; // help variable
    
      // The input file stream
      std::ifstream source;
    
      // Open and Checks i.e Fail to open file
      source.open( filename, std::ios::in | std::ios::binary );
    
      // Check if the file exists
      if( !source.is_open() )
      {
        std::cout << "Can't read image: " << filename << std::endl;
        return false;
      }
    
      // Check if the file is a valid PGM file (magic number)
      source.getline( header, 100, '\n' );
    
      if( header[0] != 'P' && header[1] != '5' )
      {
        std::cout << "Error! Invalid PGM File";
        return false;
      }
    
      // Ignoring comments
      source.getline( header, 100, '\n' );
      while( header[0] == '#' )
      {
        source.getline( header, 100, '\n' );
      }
    
      // Extracting image size
      width = strtol( header, &ptr, 0 );
      height = atoi( ptr );
    
      // Reading Gray value range
      source.getline( header, 100, '\n' );
      maxValue = strtol( header, &ptr, 0 );
    
      // Create image of given size
      if( !image->Allocate( width, height ) )
      {
        std::cout << "Error: can not create image of size [" << width << "x" << height << "] !\n";
        return false;
      }
    
      // Reading grayvalues in file
      for( unsigned int y = 0; y < height; y++ )
      {
        for( unsigned int x = 0; x < width; x++ )
        {
          Image::PixelType pixelValue;
    
          // check if 8 or 16 bit values are used
          if( maxValue > 255 )
          {
            unsigned char value16Bit[2];
            source.read( (char*) &value16Bit[0], 2 * sizeof(char) );
    
            pixelValue = static_cast<Image::PixelType> ( (value16Bit[0] & 255) << 8 ) + static_cast<Image::PixelType> ( value16Bit[1] & 255 );
          }
          else
          {
            unsigned char value8Bit;
            source.read( (char*) &value8Bit, sizeof(char) );
    
            pixelValue = static_cast<Image::PixelType> ( value8Bit );
          }
    
          image->SetPixel( x, y, pixelValue );
        }
      }
    
      return true;
    }
    
    // A MetaImage consists of a header file (-mha or .mhd) and a RAW file (.raw).
    //
    // The minimal structure of the MetaImage header is the following:
    //
    // ObjectType = Image
    // NDims = 2
    // DimSize = 181 217
    // ElementType = MET_UCHAR
    // ElementSpacing = 1.0 1.0
    // ElementByteOrderMSB = False
    // ElementDataFile = image.raw
    //
    // * ObjectType indicates that the file contains an image.
    // * NDims indicate that this is a 2D image.
    // * DimSize indicates the size of the volume in pixels along each
    //   direction.
    // * ElementType indicate the primitive type used for pixels. In this case
    //   is "unsigned char", implying that the data is digitized in 8 bits /
    //   pixel.
    // * ElementSpacing indicates the physical separation between the center of
    //   one pixel and the center of the next pixel along each direction in space.
    //   The units used are millimeters.
    // * ElementByteOrderMSB indicates is the data is encoded in little or big
    //   endian order.
    // * ElementDataFile is the name of the file containing the raw binary data
    //   of the image. This file must be in the same directory as the header.
    bool ImageIO::ReadMetaImage( const char* filename, Image* image )
    {
      // Image parameters to read from header.
      enum PixelType
      {
        CHAR, UCHAR, SHORT, USHORT
      };
    
      PixelType pixelType = CHAR;
      bool byteOrderMSB = true;
      unsigned int width = 0;
      unsigned int height = 0;
      double sx = 1.0;
      double sy = 1.0;
      std::string rawFilename = "";
    
      //
      // Read header file
      //
    
      // The file stream.
      std::ifstream headerFileStream( filename, std::ios::in );
    
      // A string to store each text line in.
      std::string textline = "";
    
      while( getline( headerFileStream, textline ) )
      {
        if( textline.find( "ObjectType" ) == 0 )
        {
          if( textline.find( "Image" ) == std::string::npos )
          {
            std::cout << "Error: File does not contain an image!" << std::endl;
            return false;
          }
        }
        else if( textline.find( "NDims" ) == 0 )
        {
          std::string::size_type equalPos = textline.find( "=" );
    
          std::string::size_type startPos = textline.find_first_not_of( " ", equalPos + 1 );
          std::string::size_type endPos = textline.find( " ", startPos + 1 );
    
          int dimension = atoi( textline.substr( startPos, endPos ).c_str() );
    
          if( dimension != 2 )
          {
            std::cout << "Error: Only images of dimension 2 are supported!" << std::endl;
            return false;
          }
        }
        else if( textline.find( "DimSize" ) == 0 )
        {
          std::string::size_type equalPos = textline.find( "=" );
    
          std::string::size_type startPos = textline.find_first_not_of( " ", equalPos + 1 );
          std::string::size_type endPos = textline.find( " ", startPos + 1 );
          width = atoi( textline.substr( startPos, endPos ).c_str() );
    
          startPos = textline.find_first_not_of( " ", endPos + 1 );
          endPos = textline.find( " ", startPos + 1 );
          height = atoi( textline.substr( startPos, endPos ).c_str() );
        }
        else if( textline.find( "ElementType" ) == 0 )
        {
          if( textline.find( "MET_CHAR" ) != std::string::npos )
          {
            pixelType = CHAR;
          }
          else if( textline.find( "MET_UCHAR" ) != std::string::npos )
          {
            pixelType = UCHAR;
          }
          else if( textline.find( "MET_SHORT" ) != std::string::npos )
          {
            pixelType = SHORT;
          }
          else if( textline.find( "MET_USHORT" ) != std::string::npos )
          {
            pixelType = USHORT;
          }
          else
          {
            std::cout << textline << "Error: Only images of type char, unsigned char, short and unsigned short are supported!" << std::endl;
            return false;
          }
        }
        else if( textline.find( "ElementSpacing" ) == 0 || textline.find( "ElementSize" ) == 0 )
        {
          std::string::size_type equalPos = textline.find( "=" );
    
          std::string::size_type startPos = textline.find_first_not_of( " ", equalPos + 1 );
          std::string::size_type endPos = textline.find( " ", startPos + 1 );
          sx = atof( textline.substr( startPos, endPos ).c_str() );
    
          startPos = textline.find_first_not_of( " ", endPos + 1 );
          endPos = textline.find( " ", startPos + 1 );
          sy = atof( textline.substr( startPos, endPos ).c_str() );
        }
        else if( textline.find( "ElementByteOrderMSB" ) == 0 )
        {
          if( textline.find( "True" ) != std::string::npos )
          {
            byteOrderMSB = true;
          }
          else if( textline.find( "False" ) != std::string::npos )
          {
            byteOrderMSB = false;
          }
          else
          {
            std::cout << textline << "Error: ElementByteOrderMSB must be 'True' or 'False'!" << std::endl;
            return false;
          }
        }
        else if( textline.find( "ElementDataFile" ) == 0 )
        {
          std::string::size_type equalPos = textline.find( "=" );
          std::string::size_type startPos = textline.find_first_not_of( " ", equalPos + 1 );
          rawFilename = textline.substr( startPos, textline.size() ).c_str();
        }
      }
    
      headerFileStream.close();
    
      // Create image with the given parameters.
      if( !image->Allocate( width, height ) )
      {
        std::cout << "Error: can not create image of size [" << width << "x" << height << "] !\n";
        return false;
      }
      image->SetSpacing( sx, sy );
    
      //
      // Read RAW file
      //
      // get path of the header file
      std::string pathName;
      if( GetFilePath( std::string( filename ), pathName ) )
      {
        rawFilename = pathName + rawFilename;
      }
    
      std::ifstream rawFileStream( rawFilename.c_str(), std::ios::in | std::ios::binary );
      if( !rawFileStream )
      {
        std::cout << "Error: Can not read raw file: " << rawFilename << std::endl;
        return false;
      }
    
      // Read grayvalues from RAW file.
      for( unsigned int y = 0; y < height; y++ )
      {
        for( unsigned int x = 0; x < width; x++ )
        {
          Image::PixelType pixelValue;
    
          // check if 8 or 16 bit values are used
          if( pixelType == SHORT || pixelType == USHORT )
          {
            unsigned char value16Bit[2];
            rawFileStream.read( (char*) &value16Bit[0], 2 * sizeof(char) );
    
            if( byteOrderMSB )
            {
              pixelValue = static_cast<Image::PixelType> ( (value16Bit[0] & 255) << 8 ) + static_cast<Image::PixelType> ( value16Bit[1] & 255 );
            }
            else
            {
              pixelValue = static_cast<Image::PixelType> ( (value16Bit[1] & 255) << 8 ) + static_cast<Image::PixelType> ( value16Bit[0] & 255 );
            }
          }
          else
          {
            unsigned char value8Bit;
            rawFileStream.read( (char*) &value8Bit, sizeof(char) );
    
            pixelValue = static_cast<Image::PixelType> ( value8Bit );
          }
    
          image->SetPixel( x, y, pixelValue );
        }
      }
    
      rawFileStream.close();
    
      // return the image
      return image;
    }
    
    //
    // WritePGMImage()
    //
    bool ImageIO::WritePGMImage( const char* filename, const Image* image )
    {
      std::ofstream destination;
    
      destination.open( filename, std::ios::binary | std::ios::out );
      if( !destination )
      {
        std::cout << "ERROR: can not open file " << filename << "!\n";
        return false;
      }
    
      // compute minimum, maximum image value
      Image::PixelType minValue = image->GetPixel( 0, 0 );
      Image::PixelType maxValue = image->GetPixel( 0, 0 );
      const unsigned int size = image->GetSizeX() * image->GetSizeY();
    
      for( unsigned int index = 0; index < size; index++ )
      {
        const Image::PixelType value = image->GetPixel( index );
    
        if( value < minValue )
          minValue = value;
        if( value > maxValue )
          maxValue = value;
      }
    
      if( minValue < 0 )
      {
        std::cout << "Warning: Negative gray values are not supported in PGM format and will be set to 0!\n";
      }
    
      // maxvalue of 0 not supported by most readers
      if(maxValue == 0) maxValue=1;
    
      // writes header into the Destination
      destination << "P5" << std::endl;
      destination << "# Created By IMI Luebeck" << std::endl;
      destination << image->GetSizeX() << " " << image->GetSizeY() << std::endl;
      destination << (int)maxValue << std::endl;
    
      for( unsigned int index = 0; index < size; index++ )
      {
        Image::PixelType value = image->GetPixel( index );
    
        if( value < 0 ) value = 0;
    
        // check for 8bit or 16bit storage
        if( maxValue > 255 )
        {
          char buffer[2];
          buffer[0] = static_cast<char> ( (value >> 8) & 255 );
          buffer[1] = static_cast<char> ( value & 255 );
          destination.write( buffer, 2 * sizeof(char) );
        }
        else
        {
          char buffer;
          buffer = static_cast<char> ( value );
          destination.write( &buffer, sizeof(char) );
        }
      }
    
      destination.close();
    
      return true;
    }
    
    //
    // WriteMetaImage()
    //
    bool ImageIO::WriteMetaImage( const char* filename, const Image* image )
    {
      // Byte order to write file (true = Big Endian, false = Little Endian).
      bool byteOrderMSB = false;
    
      // Get string filename.
      std::string fileNameString = filename;
    
      // Get full filename of the raw file (required to open file stream).
      std::string rawFileNameString = fileNameString.substr( 0, fileNameString.length() - 3 ).append( "raw" );
    
      // Get base filename of the raw file (required to write in the header file).
      std::string::size_type baseStartPos = rawFileNameString.find_last_of( "/" ) + 1;
      std::string rawFileNameBase = rawFileNameString.substr( baseStartPos, rawFileNameString.length() - baseStartPos );
    
      //
      // Write header file
      //
      // Open header file for writing.
      std::ofstream headerFileStream;
      headerFileStream.open( filename, std::ios::out );
    
      // Write data in header file.
      if( headerFileStream.is_open() )
      {
        headerFileStream << "ObjectType = Image" << std::endl;
        headerFileStream << "NDims = 2" << std::endl;
        headerFileStream << "DimSize = " << image->GetSizeX() << " " << image->GetSizeY() << std::endl;
        headerFileStream << "ElementType = MET_SHORT" << std::endl;
        headerFileStream << "ElementSpacing = " << image->GetSpacingX() << " " << image->GetSpacingY() << std::endl;
        if( byteOrderMSB )
        {
          headerFileStream << "ElementByteOrderMSB = True" << std::endl;
        }
        else
        {
          headerFileStream << "ElementByteOrderMSB = False" << std::endl;
        }
        headerFileStream << "ElementDataFile = " << rawFileNameBase << std::endl;
      }
      else
      {
        std::cout << "Error: Failed to open output header!" << std::endl;
        return false;
      }
    
      // Close header file.
      headerFileStream.close();
    
      //
      // Write RAW file
      //
      std::ofstream rawFileStream( rawFileNameString.c_str(), std::ios::binary | std::ios::out );
      if( !rawFileStream )
      {
        std::cout << "ERROR: can not open file " << filename << "!\n";
        return false;
      }
    
      for( unsigned int y = 0; y < image->GetSizeY(); y++ )
      {
        for( unsigned int x = 0; x < image->GetSizeX(); x++ )
        {
          Image::PixelType pixelValue = image->GetPixel( x, y );
    
          char buffer[2];
    
          if( byteOrderMSB )
          {
            buffer[0] = static_cast<char> ( (pixelValue >> 8) & 255 );
            buffer[1] = static_cast<char> ( pixelValue & 255 );
          }
          else
          {
            buffer[1] = static_cast<char> ( (pixelValue >> 8) & 255 );
            buffer[0] = static_cast<char> ( pixelValue & 255 );
          }
          rawFileStream.write( buffer, 2 * sizeof(char) );
        }
      }
    
      rawFileStream.close();
    
      return true;
    }
    
    //
    // GetFilePath()
    //
    bool ImageIO::GetFilePath( const std::string fileName, std::string &path )
    {
      size_t found;
      found = fileName.find_last_of( "\\/" );
      if( found != std::string::npos )
      {
        path = fileName.substr( 0, found + 1 );
      }
      else
      {
        path = "";
        return false;
      }
      return true;
    }
    

    Das sind die wichtigsten Klassen welche für dilatation und erosion gebraucht werden.



  • und du glaubst, dass sich hier jemand für dich über 1000 Zeilen code anschaut?

    Liß mal die oben gepinnten Threads, wie zum Beispiel "wie man fragen richtig stellt". Stichwort Minimalbeispiel.



  • Ich bin sogar durch gegangen. Und da steht auch nicht drin wonach ich gefragt habe: Wo ist die Erosionsmaske definiert und welchen Inhalt hat sie?

    Bitte Xeno, schau' Dir meinen Code an und prüfe, ob Du etwas in der Art bei Dir hast. Ansonsten schau' Dir bitte noch mal die theoretische Definition von Erosion und Dilatation an.



  • also die maske ist eine 3x3 mit true also 1 als wert gesetzt. ich soll jetzt nur noch die operation implementieren. ich weiss was eine erosion ist nämlich eine verundung bzw. minimierung. Aber das ergebnis scheint nicht richtig zu sein.


Anmelden zum Antworten