예제 #1
0
//----------------------------------------------------------------------------
void ImageUtility2::Close8(Image2<int> const& input, bool zeroExterior,
                           Image2<int>& output)
{
    Image2<int> temp(input.GetDimension(0), input.GetDimension(1));
    Dilate8(input, temp);
    Erode8(temp, zeroExterior, output);
}
예제 #2
0
//----------------------------------------------------------------------------
void ImageUtility2::Open4(Image2<int> const& input, bool zeroExterior,
                          Image2<int>& output)
{
    Image2<int> temp(input.GetDimension(0), input.GetDimension(1));
    Erode4(input, zeroExterior, temp);
    Dilate4(temp, output);
}
예제 #3
0
//----------------------------------------------------------------------------
void ImageUtility2::Close(Image2<int> const& input, bool zeroExterior,
                          int numNeighbors, std::array<int, 2> const* neighbors,
                          Image2<int>& output)
{
    Image2<int> temp(input.GetDimension(0), input.GetDimension(1));
    Dilate(input, numNeighbors, neighbors, temp);
    Erode(temp, zeroExterior, numNeighbors, neighbors, output);
}
예제 #4
0
//----------------------------------------------------------------------------
bool ImageUtility2::MarkInterior(Image2<int>& image, int value,
                                 bool (*function)(Image2<int>&,int,int))
{
    int const dim0 = image.GetDimension(0);
    int const dim1 = image.GetDimension(1);
    bool noInterior = true;
    for (int y = 0; y < dim1; ++y)
    {
        for (int x = 0; x < dim0; ++x)
        {
            if (image(x, y) > 0)
            {
                if (function(image, x, y))
                {
                    image(x, y) = value;
                    noInterior = false;
                }
                else
                {
                    image(x, y) = 1;
                }
            }
        }
    }
    return noInterior;
}
예제 #5
0
//----------------------------------------------------------------------------
void ImageUtility2::Dilate(Image2<int> const& input, int numNeighbors,
                           std::array<int, 2> const* neighbors, Image2<int>& output)
{
    // If the assertion is triggered, the function will run but the output
    // will not be correct.
    LogAssert(&output != &input, "Input and output must be different.");

    output = input;

    // If the pixel at (x,y) is 1, then the pixels at (x+dx,y+dy) are set to 1
    // where (dx,dy) is in the 'neighbors' array.  Boundary testing is used to
    // avoid accessing out-of-range pixels.
    int const dim0 = input.GetDimension(0);
    int const dim1 = input.GetDimension(1);
    for (int y = 0; y < dim1; ++y)
    {
        for (int x = 0; x < dim0; ++x)
        {
            if (input(x, y) == 1)
            {
                for (int j = 0; j < numNeighbors; ++j)
                {
                    int xNbr = x + neighbors[j][0];
                    int yNbr = y + neighbors[j][1];
                    if (0 <= xNbr && xNbr < dim0 && 0 <= yNbr && yNbr < dim1)
                    {
                        output(xNbr, yNbr) = 1;
                    }
                }
            }
        }
    }
}
예제 #6
0
//----------------------------------------------------------------------------
bool ImageUtility2::ClearInteriorAdjacent(Image2<int>& image, int value)
{
    int const dim0 = image.GetDimension(0);
    int const dim1 = image.GetDimension(1);
    bool noRemoval = true;
    for (int y = 0; y < dim1; ++y)
    {
        for (int x = 0; x < dim0; ++x)
        {
            if (image(x, y) == 1)
            {
                bool interiorAdjacent =
                    image(x-1, y-1) == value ||
                    image(x  , y-1) == value ||
                    image(x+1, y-1) == value ||
                    image(x+1, y  ) == value ||
                    image(x+1, y+1) == value ||
                    image(x  , y+1) == value ||
                    image(x-1, y+1) == value ||
                    image(x-1, y  ) == value;

                if (interiorAdjacent && !IsArticulation(image, x, y))
                {
                    image(x, y) = 0;
                    noRemoval = false;
                }
            }
        }
    }
    return noRemoval;
}
예제 #7
0
//---------------------------------------------------------------------------
void SetInitial2 (Image2<float>& initial)
{
    const int n0 = initial.GetDimension(0);
    const int n1 = initial.GetDimension(1);
    for (int i1 = 0; i1 < n1; ++i1)
    {
        float x1 = -1.0f + 2.0f*i1/(float)(n1-1);
        float value1 = 1.0f - x1*x1;
        for (int i0 = 0; i0 < n0; ++i0)
        {
            float x0 = -1.0f + 2.0f*i0/(float)(n0-1);
            float value0 = 1.0f - x0*x0;
            initial(i0, i1) = value0*value1;
        }
    }
}
예제 #8
0
//----------------------------------------------------------------------------
void ImageUtility2::Erode(Image2<int> const& input, bool zeroExterior,
                          int numNeighbors, std::array<int, 2> const* neighbors,
                          Image2<int>& output)
{
    // If the assertion is triggered, the function will run but the output
    // will not be correct.
    LogAssert(&output != &input, "Input and output must be different.");

    output = input;

    // If the pixel at (x,y) is 1, it is changed to 0 when at least one
    // neighbor (x+dx,y+dy) is 0, where (dx,dy) is in the 'neighbors'
    // array.
    int const dim0 = input.GetDimension(0);
    int const dim1 = input.GetDimension(1);
    for (int y = 0; y < dim1; ++y)
    {
        for (int x = 0; x < dim0; ++x)
        {
            if (input(x, y) == 1)
            {
                for (int j = 0; j < numNeighbors; ++j)
                {
                    int xNbr = x + neighbors[j][0];
                    int yNbr = y + neighbors[j][1];
                    if (0 <= xNbr && xNbr < dim0 && 0 <= yNbr && yNbr < dim1)
                    {
                        if (input(xNbr, yNbr) == 0)
                        {
                            output(x, y) = 0;
                            break;
                        }
                    }
                    else if (zeroExterior)
                    {
                        output(x, y) = 0;
                        break;
                    }
                }
            }
        }
    }
}
예제 #9
0
//----------------------------------------------------------------------------
void ImageUtility2::L2Check(int x, int y, int dx, int dy, Image2<int>& xNear,
                            Image2<int>& yNear, Image2<int>& dist)
{
    int const dim0 = dist.GetDimension(0);
    int const dim1 = dist.GetDimension(1);
    int xp = x + dx, yp = y + dy;
    if (0 <= xp && xp < dim0 && 0 <= yp && yp < dim1)
    {
        if (dist(xp, yp) < dist(x, y))
        {
            int dx0 = xNear(xp, yp) - x;
            int dy0 = yNear(xp, yp) - y;
            int newDist = dx0*dx0 + dy0*dy0;
            if (newDist < dist(x, y))
            {
                xNear(x, y) = xNear(xp, yp);
                yNear(x, y) = yNear(xp, yp);
                dist(x, y) = newDist;
            }
        }
    }
}
예제 #10
0
//----------------------------------------------------------------------------
void ImageUtility2::GetL1Distance(Image2<int>& image, int& maxDistance,
                                  int& xMax, int& yMax)
{
    int const dim0 = image.GetDimension(0);
    int const dim1 = image.GetDimension(1);
    int const dim0m1 = dim0 - 1;
    int const dim1m1 = dim1 - 1;

    // Use a grass-fire approach, computing distance from boundary to
    // interior one pass at a time.
    bool changeMade = true;
    int distance;
    for (distance = 1, xMax = 0, yMax = 0; changeMade; ++distance)
    {
        changeMade = false;
        int distanceP1 = distance + 1;
        for (int y = 1; y < dim1m1; ++y)
        {
            for (int x = 1; x < dim0m1; ++x)
            {
                if (image(x, y) == distance)
                {
                    if (image(x-1, y) >= distance
                            &&  image(x+1, y) >= distance
                            &&  image(x, y-1) >= distance
                            &&  image(x, y+1) >= distance)
                    {
                        image(x, y) = distanceP1;
                        xMax = x;
                        yMax = y;
                        changeMade = true;
                    }
                }
            }
        }
    }

    maxDistance = --distance;
}
예제 #11
0
//----------------------------------------------------------------------------
void ImageUtility2::GetSkeleton(Image2<int>& image)
{
    int const dim0 = image.GetDimension(0);
    int const dim1 = image.GetDimension(1);

    // Trim pixels, mark interior as 4.
    bool notDone = true;
    while (notDone)
    {
        if (MarkInterior(image, 4, Interior4))
        {
            // No interior pixels, trimmed set is at most 2-pixels thick.
            notDone = false;
            continue;
        }

        if (ClearInteriorAdjacent(image, 4))
        {
            // All remaining interior pixels are either articulation points
            // or part of blobs whose boundary pixels are all articulation
            // points.  An example of the latter case is shown below.  The
            // background pixels are marked with '.' rather than '0' for
            // readability.  The interior pixels are marked with '4' and the
            // boundary pixels are marked with '1'.
            //
            //   .........
            //   .....1...
            //   ..1.1.1..
            //   .1.141...
            //   ..14441..
            //   ..1441.1.
            //   .1.11.1..
            //   ..1..1...
            //   .........
            //
            // This is a pathological problem where there are many small holes
            // (0-pixel with north, south, west, and east neighbors all
            // 1-pixels) that your application can try to avoid by an initial
            // pass over the image to fill in such holes.  Of course, you do
            // have problems with checkerboard patterns...
            notDone = false;
            continue;
        }
    }

    // Trim pixels, mark interior as 3.
    notDone = true;
    while (notDone)
    {
        if (MarkInterior(image, 3, Interior3))
        {
            // No interior pixels, trimmed set is at most 2-pixels thick.
            notDone = false;
            continue;
        }

        if (ClearInteriorAdjacent(image, 3))
        {
            // All remaining 3-values can be safely removed since they are
            // not articulation points and the removal will not cause new
            // holes.
            for (int y = 0; y < dim1; ++y)
            {
                for (int x = 0; x < dim0; ++x)
                {
                    if (image(x, y) == 3 && !IsArticulation(image, x, y))
                    {
                        image(x, y) = 0;
                    }
                }
            }
            notDone = false;
            continue;
        }
    }

    // Trim pixels, mark interior as 2.
    notDone = true;
    while (notDone)
    {
        if (MarkInterior(image, 2, Interior2))
        {
            // No interior pixels, trimmed set is at most 1-pixel thick.
            // Call it a skeleton.
            notDone = false;
            continue;
        }

        if (ClearInteriorAdjacent(image, 2))
        {
            // Removes 2-values that are not articulation points.
            for (int y = 0; y < dim1; ++y)
            {
                for (int x = 0; x < dim0; ++x)
                {
                    if (image(x, y) == 2 && !IsArticulation(image, x, y))
                    {
                        image(x, y) = 0;
                    }
                }
            }
            notDone = false;
            continue;
        }
    }

    // Make the skeleton a binary image.
    size_t const numPixels = image.GetNumPixels();
    for (size_t i = 0; i < numPixels; ++i)
    {
        if (image[i] != 0)
        {
            image[i] = 1;
        }
    }
}
예제 #12
0
//----------------------------------------------------------------------------
void ImageUtility2::GetL2Distance(Image2<int> const& image,
                                  float& maxDistance, int& xMax, int& yMax, Image2<float>& transform)
{
    // This program calculates the Euclidean distance transform of a binary
    // input image.  The adaptive algorithm is guaranteed to give exact
    // distances for all distances < 100.  Algorithm sent to me by John Gauch.
    //
    // From John Gauch at University of Kansas:
    // The basic idea is similar to a EDT described recently in PAMI by
    // Laymarie from McGill.  By keeping the dx and dy offset to the nearest
    // edge (feature) point in the image, we can search to see which dx dy is
    // closest to a given point by examining a set of neighbors.  The Laymarie
    // method (and Borgfors) look at a fixed 3x3 or 5x5 neighborhood and call
    // it a day.  What we did was calculate (painfully) what neighborhoods you
    // need to look at to guarentee that the exact distance is obtained.  Thus,
    // you will see in the code, that we L2Check the current distance and
    // depending on what we have so far, we extend the search region.  Since
    // our algorithm for L2Checking the exactness of each neighborhood is on
    // the order N^4, we have only gone to N=100.  In theory, you could make
    // this large enough to get all distances exact.  We have implemented the
    // algorithm to get all distances < 100 to be exact.
    int const dim0 = image.GetDimension(0);
    int const dim1 = image.GetDimension(1);
    int const dim0m1 = dim0 - 1;
    int const dim1m1 = dim1 - 1;
    int x, y, distance;

    // Create and initialize intermediate images.
    Image2<int> xNear(dim0, dim1);
    Image2<int> yNear(dim0, dim1);
    Image2<int> dist(dim0, dim1);
    for (y = 0; y < dim1; ++y)
    {
        for (x = 0; x < dim0; ++x)
        {
            if (image(x, y) != 0)
            {
                xNear(x, y) = 0;
                yNear(x, y) = 0;
                dist(x, y) = std::numeric_limits<int>::max();
            }
            else
            {
                xNear(x, y) = x;
                yNear(x, y) = y;
                dist(x, y) = 0;
            }
        }
    }

    int const K1 = 1;
    int const K2 = 169;   // 13^2
    int const K3 = 961;   // 31^2
    int const K4 = 2401;  // 49^2
    int const K5 = 5184;  // 72^2

    // Pass in the ++ direction.
    for (y = 0; y < dim1; ++y)
    {
        for (x = 0; x < dim0; ++x)
        {
            distance = dist(x, y);
            if (distance > K1)
            {
                L2Check(x, y, -1,  0, xNear, yNear, dist);
                L2Check(x, y, -1, -1, xNear, yNear, dist);
                L2Check(x, y,  0, -1, xNear, yNear, dist);
            }
            if (distance > K2)
            {
                L2Check(x, y, -2, -1, xNear, yNear, dist);
                L2Check(x, y, -1, -2, xNear, yNear, dist);
            }
            if (distance > K3)
            {
                L2Check(x, y, -3, -1, xNear, yNear, dist);
                L2Check(x, y, -3, -2, xNear, yNear, dist);
                L2Check(x, y, -2, -3, xNear, yNear, dist);
                L2Check(x, y, -1, -3, xNear, yNear, dist);
            }
            if (distance > K4)
            {
                L2Check(x, y, -4, -1, xNear, yNear, dist);
                L2Check(x, y, -4, -3, xNear, yNear, dist);
                L2Check(x, y, -3, -4, xNear, yNear, dist);
                L2Check(x, y, -1, -4, xNear, yNear, dist);
            }
            if (distance > K5)
            {
                L2Check(x, y, -5, -1, xNear, yNear, dist);
                L2Check(x, y, -5, -2, xNear, yNear, dist);
                L2Check(x, y, -5, -3, xNear, yNear, dist);
                L2Check(x, y, -5, -4, xNear, yNear, dist);
                L2Check(x, y, -4, -5, xNear, yNear, dist);
                L2Check(x, y, -2, -5, xNear, yNear, dist);
                L2Check(x, y, -3, -5, xNear, yNear, dist);
                L2Check(x, y, -1, -5, xNear, yNear, dist);
            }
        }
    }

    // Pass in -- direction.
    for (y = dim1m1; y >= 0; --y)
    {
        for (x = dim0m1; x >= 0; --x)
        {
            distance = dist(x, y);
            if (distance > K1)
            {
                L2Check(x, y, 1, 0, xNear, yNear, dist);
                L2Check(x, y, 1, 1, xNear, yNear, dist);
                L2Check(x, y, 0, 1, xNear, yNear, dist);
            }
            if (distance > K2)
            {
                L2Check(x, y, 2, 1, xNear, yNear, dist);
                L2Check(x, y, 1, 2, xNear, yNear, dist);
            }
            if (distance > K3)
            {
                L2Check(x, y, 3, 1, xNear, yNear, dist);
                L2Check(x, y, 3, 2, xNear, yNear, dist);
                L2Check(x, y, 2, 3, xNear, yNear, dist);
                L2Check(x, y, 1, 3, xNear, yNear, dist);
            }
            if (distance > K4)
            {
                L2Check(x, y, 4, 1, xNear, yNear, dist);
                L2Check(x, y, 4, 3, xNear, yNear, dist);
                L2Check(x, y, 3, 4, xNear, yNear, dist);
                L2Check(x, y, 1, 4, xNear, yNear, dist);
            }
            if (distance > K5)
            {
                L2Check(x, y, 5, 1, xNear, yNear, dist);
                L2Check(x, y, 5, 2, xNear, yNear, dist);
                L2Check(x, y, 5, 3, xNear, yNear, dist);
                L2Check(x, y, 5, 4, xNear, yNear, dist);
                L2Check(x, y, 4, 5, xNear, yNear, dist);
                L2Check(x, y, 2, 5, xNear, yNear, dist);
                L2Check(x, y, 3, 5, xNear, yNear, dist);
                L2Check(x, y, 1, 5, xNear, yNear, dist);
            }
        }
    }

    // Pass in the +- direction.
    for (y = dim1m1; y >= 0; --y)
    {
        for (x = 0; x < dim0; ++x)
        {
            distance = dist(x, y);
            if (distance > K1)
            {
                L2Check(x, y, -1, 0, xNear, yNear, dist);
                L2Check(x, y, -1, 1, xNear, yNear, dist);
                L2Check(x, y,  0, 1, xNear, yNear, dist);
            }
            if (distance > K2)
            {
                L2Check(x, y, -2, 1, xNear, yNear, dist);
                L2Check(x, y, -1, 2, xNear, yNear, dist);
            }
            if (distance > K3)
            {
                L2Check(x, y, -3, 1, xNear, yNear, dist);
                L2Check(x, y, -3, 2, xNear, yNear, dist);
                L2Check(x, y, -2, 3, xNear, yNear, dist);
                L2Check(x, y, -1, 3, xNear, yNear, dist);
            }
            if (distance > K4)
            {
                L2Check(x, y, -4, 1, xNear, yNear, dist);
                L2Check(x, y, -4, 3, xNear, yNear, dist);
                L2Check(x, y, -3, 4, xNear, yNear, dist);
                L2Check(x, y, -1, 4, xNear, yNear, dist);
            }
            if (distance > K5)
            {
                L2Check(x, y, -5, 1, xNear, yNear, dist);
                L2Check(x, y, -5, 2, xNear, yNear, dist);
                L2Check(x, y, -5, 3, xNear, yNear, dist);
                L2Check(x, y, -5, 4, xNear, yNear, dist);
                L2Check(x, y, -4, 5, xNear, yNear, dist);
                L2Check(x, y, -2, 5, xNear, yNear, dist);
                L2Check(x, y, -3, 5, xNear, yNear, dist);
                L2Check(x, y, -1, 5, xNear, yNear, dist);
            }
        }
    }

    // Pass in the -+ direction.
    for (y = 0; y < dim1; ++y)
    {
        for (x = dim0m1; x >= 0; --x)
        {
            distance = dist(x, y);
            if (distance > K1)
            {
                L2Check(x, y, 1,  0, xNear, yNear, dist);
                L2Check(x, y, 1, -1, xNear, yNear, dist);
                L2Check(x, y, 0, -1, xNear, yNear, dist);
            }
            if (distance > K2)
            {
                L2Check(x, y, 2, -1, xNear, yNear, dist);
                L2Check(x, y, 1, -2, xNear, yNear, dist);
            }
            if (distance > K3)
            {
                L2Check(x, y, 3, -1, xNear, yNear, dist);
                L2Check(x, y, 3, -2, xNear, yNear, dist);
                L2Check(x, y, 2, -3, xNear, yNear, dist);
                L2Check(x, y, 1, -3, xNear, yNear, dist);
            }
            if (distance > K4)
            {
                L2Check(x, y, 4, -1, xNear, yNear, dist);
                L2Check(x, y, 4, -3, xNear, yNear, dist);
                L2Check(x, y, 3, -4, xNear, yNear, dist);
                L2Check(x, y, 1, -4, xNear, yNear, dist);
            }
            if (distance > K5)
            {
                L2Check(x, y, 5, -1, xNear, yNear, dist);
                L2Check(x, y, 5, -2, xNear, yNear, dist);
                L2Check(x, y, 5, -3, xNear, yNear, dist);
                L2Check(x, y, 5, -4, xNear, yNear, dist);
                L2Check(x, y, 4, -5, xNear, yNear, dist);
                L2Check(x, y, 2, -5, xNear, yNear, dist);
                L2Check(x, y, 3, -5, xNear, yNear, dist);
                L2Check(x, y, 1, -5, xNear, yNear, dist);
            }
        }
    }

    xMax = 0;
    yMax = 0;
    maxDistance = 0.0f;
    for (y = 0; y < dim1; ++y)
    {
        for (x = 0; x < dim0; ++x)
        {
            float fdistance = sqrt((float)dist(x, y));
            if (fdistance > maxDistance)
            {
                maxDistance = fdistance;
                xMax = x;
                yMax = y;
            }
            transform(x, y) = fdistance;
        }
    }
}
예제 #13
0
//----------------------------------------------------------------------------
bool SaveBMP32 (const std::string& name, const Image2<PixelBGRA8>& image)
{
    FILE* outFile = fopen(name.c_str(), "wb");
    if (!outFile)
    {
        assertion(false, "Cannot open file '%s' for write.\n", name.c_str());
        return false;
    }

    const int numPixels = image.GetNumPixels();
    const int numBytes = 4*image.GetNumPixels();
    const int size = sizeOfBitMapFileHeader + sizeOfBitMapInfoHeader;

    PrivateBitMapFileHeader fileHeader;
    fileHeader.bfType = 0x4d42;
    fileHeader.bfSize = size + numBytes;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = size;
    size_t numWritten = fwrite(&fileHeader.bfType, sizeof(unsigned short),
        1, outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (bfType).\n");
        fclose(outFile);
        return false;
    }

    numWritten = fwrite(&fileHeader.bfSize, sizeof(unsigned long), 1,
        outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (bfSize).\n");
        fclose(outFile);
        return false;
    }

    numWritten = fwrite(&fileHeader.bfReserved1, sizeof(unsigned short), 1,
        outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (bfReserved1).\n");
        fclose(outFile);
        return false;
    }

    numWritten = fwrite(&fileHeader.bfReserved2, sizeof(unsigned short), 1,
        outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (bfReserved2).\n");
        fclose(outFile);
        return false;
    }

    numWritten = fwrite(&fileHeader.bfOffBits, sizeof(unsigned long), 1,
        outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (bfOffBits).\n");
        fclose(outFile);
        return false;
    }

    PrivateBitMapInfoHeader infoHeader;
    infoHeader.biSize = sizeOfBitMapInfoHeader;
    infoHeader.biWidth = image.GetDimension(0);
    infoHeader.biHeight = image.GetDimension(1);
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 32;
    infoHeader.biCompression = BI_RGB;
    infoHeader.biSizeImage = 0;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;
    numWritten = fwrite(&infoHeader, sizeOfBitMapInfoHeader, 1, outFile);
    if (numWritten != 1)
    {
        assertion(false, "Failed to write (infoHeader).\n");
        fclose(outFile);
        return false;
    }

    PixelBGRA8* source = image.GetPixels1D();
    numWritten = fwrite(source, sizeof(PixelBGRA8), numPixels, outFile);
    if (numWritten != (size_t)numPixels)
    {
        assertion(false, "Failed to write (source).\n");
        fclose(outFile);
        return false;
    }

    fclose(outFile);
    return true;
}