//----------------------------------------------------------------------------
void ImageUtility2::GetComponents(int numNeighbors, int const* delta,
                                  Image2<int>& image, std::vector<std::vector<size_t>>& components)
{
    size_t const numPixels = image.GetNumPixels();
    int* numElements = new int[numPixels];
    size_t* vstack = new size_t[numPixels];
    size_t i, numComponents = 0;
    int label = 2;
    for (i = 0; i < numPixels; ++i)
    {
        if (image[i] == 1)
        {
            int top = -1;
            vstack[++top] = i;

            int& count = numElements[numComponents + 1];
            count = 0;
            while (top >= 0)
            {
                size_t v = vstack[top];
                image[v] = -1;
                int j;
                for (j = 0; j < numNeighbors; ++j)
                {
                    size_t adj = v + delta[j];
                    if (image[adj] == 1)
                    {
                        vstack[++top] = adj;
                        break;
                    }
                }
                if (j == numNeighbors)
                {
                    image[v] = label;
                    ++count;
                    --top;
                }
            }

            ++numComponents;
            ++label;
        }
    }
    delete[] vstack;

    if (numComponents > 0)
    {
        components.resize(numComponents + 1);
        for (i = 1; i <= numComponents; ++i)
        {
            components[i].resize(numElements[i]);
            numElements[i] = 0;
        }

        for (i = 0; i < numPixels; ++i)
        {
            int value = image[i];
            if (value != 0)
            {
                // Labels started at 2 to support the depth-first search,
                // so they need to be decremented for the correct labels.
                image[i] = --value;
                components[value][numElements[value]] = i;
                ++numElements[value];
            }
        }
    }
    delete[] numElements;
}
//----------------------------------------------------------------------------
bool ImageUtility2::ExtractBoundary(int x, int y, Image2<int>& image,
                                    std::vector<size_t>& boundary)
{
    // Find a first boundary pixel.
    size_t const numPixels = image.GetNumPixels();
    size_t i;
    for (i = image.GetIndex(x, y); i < numPixels; ++i)
    {
        if (image[i])
        {
            break;
        }
    }
    if (i == numPixels)
    {
        // No boundary pixel found.
        return false;
    }

    int const dx[8] = { -1,  0, +1, +1, +1,  0, -1, -1 };
    int const dy[8] = { -1, -1, -1,  0, +1, +1, +1,  0 };

    // Create a new point list that contains the first boundary point.
    boundary.push_back(i);

    // The direction from background 0 to boundary pixel 1 is (dx[7],dy[7]).
    std::array<int,2> coord = image.GetCoordinates(i);
    int x0 = coord[0], y0 = coord[1];
    int cx = x0, cy = y0;
    int nx = x0-1, ny = y0, dir = 7;

    // Traverse the boundary in clockwise order.  Mark visited pixels as 2.
    image(cx, cy) = 2;
    bool notDone = true;
    while (notDone)
    {
        int j, nbr;
        for (j = 0, nbr = dir; j < 8; ++j, nbr = (nbr + 1) % 8)
        {
            nx = cx + dx[nbr];
            ny = cy + dy[nbr];
            if (image(nx, ny))  // next boundary pixel found
            {
                break;
            }
        }

        if (j == 8)  // (cx,cy) is isolated
        {
            notDone = false;
            continue;
        }

        if (nx == x0 && ny == y0)  // boundary traversal completed
        {
            notDone = false;
            continue;
        }

        // (nx,ny) is next boundary point, add point to list.  Note that
        // the index for the pixel is computed for the original image, not
        // for the larger temporary image.
        boundary.push_back(image.GetIndex(nx, ny));

        // Mark visited pixels as 2.
        image(nx, ny) = 2;

        // Start search for next point.
        cx = nx;
        cy = ny;
        dir = (j + 5 + dir) % 8;
    }

    return true;
}
//----------------------------------------------------------------------------
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;
        }
    }
}
Esempio n. 4
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;
}