Esempio n. 1
0
/*
Convolution filter matrix example formats:
{0, 1,2}
{ {0,1,2}, {1,2,1}, {0, 1, 0}}
*/
void extractConvolveFilterMatrix(topologyConfigSpec_t &params, std::istringstream &ss)
{
    char c;
    enum state_t { INIT, LEFTBRACE, RIGHTBRACE, COMMA, NUM };
    enum action_t { SKIP, ILL, PLINC, PLDECX, STONYINC, STONXINC, ACCUM };
    state_t lastState = INIT;
    state_t newState = INIT;
    int braceLevel = 0;
    vector<float> row;
    vector<vector<float>> mat;
    float num = 0.0;

    action_t table[5][5] = {
      /*                 INIT LEFTBRACE RIGHTBRACE COMMA     NUM  */
      /* INIT */       { ILL, PLINC,    ILL,       ILL,      ILL   },
      /* LEFTBRACE */  { ILL, PLINC,    ILL,       ILL,      ACCUM },
      /* RIGHTBRACE */ { ILL, ILL,      PLDECX,    SKIP,     ILL   },
      /* COMMA */      { ILL, PLINC,    ILL,       ILL,      ACCUM },
      /* DIGIT */      { ILL, ILL,      STONYINC,  STONXINC, ACCUM },
    };

    bool done = false;
    while (!done && ss) {
        ss >> c;
        if (isspace(c)) {
            continue;
        } else if (c == '{') {
            newState = LEFTBRACE;
        } else if (c == '}') {
            newState = RIGHTBRACE;
        } else if (c == ',') {
            newState = COMMA;
        } else if (c == '-' || c == '+' || c == '.' || isdigit(c)) {
            newState = NUM;
        } else {
            configErrorThrow(params, "Warning: Internal error in parsing convolve filter matrix spec");
        }

        action_t action = table[lastState][newState];

        switch(action) {
        case SKIP:
            break;
        case ILL:
            configErrorThrow(params, "Syntax error in convolve filter matrix spec");
            break;
        case PLINC:
            ++braceLevel;
            break;
        case PLDECX:
            --braceLevel;
            if (braceLevel != 0) {
                configErrorThrow(params, "Syntax error in convolve filter matrix spec");
            }
            done = true;
            break;
        case STONYINC:
            row.push_back(num); // Add the element to the row
            mat.push_back(row); // Add the row to the matrix
            row.clear();
            num = 0.0; // Start a new number after this
            if (--braceLevel == 0) {
                done = true;
            }
            break;
        case STONXINC:
            row.push_back(num); // Add the element to the row
            num = 0.0; // Start a new number after this
            break;
        case ACCUM:
            // We've got the first char of the number in c, which can be -, +, ., or a digit.
            // Now gather the rest of the numeric string:
            string numstr;
            numstr.clear();
            numstr.push_back(c);
            while (ss.peek() == '.' || isdigit(ss.peek())) {
                char cc;
                ss >> cc;
                numstr.push_back(cc);
            }
            num = strtod(numstr.c_str(), NULL);
            break;
        }

        lastState = newState;
    }

    // Check that all rows have the same size:

    unsigned firstRowSize = mat[0].size();
    if (0 != count_if(mat.begin() + 1, mat.end(), [firstRowSize](vector<float> row) {
             return row.size() != firstRowSize; })) {
        configErrorThrow(params, "Error in topology config file: inconsistent row size in convolve filter matrix spec");
    }

    // We'll create (or recreate) a one-element flatConvolveMatrix in the params structure:
    // Convolution filtering only needs a single convolve matrix, so only element zero is
    // used in params.flatConvolveMatrix. That one element will be a flattened
    // container of the 2D convolve matrix:

    params.flatConvolveMatrix.clear();
    params.flatConvolveMatrix.push_back(vector<float>()); // Start with one empty container for one kernel
    params.flatConvolveMatrix.back().assign(mat.size() * mat[0].size(), 0);

//    for (auto &row : mat) {
//        for (auto val : row) {
    for (uint32_t row = 0; row < mat.size(); ++row) {
        for (uint32_t col = 0; col < mat[row].size(); ++col) {
            params.flatConvolveMatrix.back()[flattenXY(col, row, mat.size())] = mat[row][col];
        }
    }

    // The matrix is arranged so that we can access elements as [x][y]:
    params.kernelSize.x = mat.size();
    params.kernelSize.y = mat[0].size();
}
Esempio n. 2
0
// Extract the input data from the specified file and save the data in the data container.
// Returns the nonzero image size if successful, else returns 0,0.
//
xySize ImageReaderBMP::getData(std::string const &filename, std::vector<float> &dataContainer, ColorChannel_t colorChannel)
{
	FILE* f;
	fopen_s(&f, filename.c_str(), "rb");

    if (f == NULL) {
        return { 0, 0 };
    }

    // Read the BMP header to get the image dimensions:

    unsigned char info[54];
    if (fread(info, sizeof(unsigned char), 54, f) != 54) {
        fclose(f);
        return { 0, 0 };
    }

    if (info[0] != 'B' || info[1] != 'M') {
        fclose(f);
        return { 0, 0 };
    }

    // Verify the offset to the pixel data. It should be the same size as the info[] data read above.

    size_t dataOffset = (info[13] << 24)
                      + (info[12] << 16)
                      + (info[11] << 8)
                      +  info[10];

    // Verify that the file contains 24 bits (3 bytes) per pixel (red, green blue at 8 bits each):

    int pixelDepth = (info[29] << 8) + info[28];
    if (pixelDepth != 24) {
        fclose(f);
        return { 0, 0 };
    }

    // This method of converting 4 bytes to a uint32_t is portable for little- or
    // big-endian environments:

    uint32_t width = (info[21] << 24)
                   + (info[20] << 16)
                   + (info[19] << 8)
                   +  info[18];

    uint32_t height = (info[25] << 24)
                    + (info[24] << 16)
                    + (info[23] << 8)
                    +  info[22];

    // Position the read pointer to the first byte of pixel data:

    if (fseek(f, dataOffset, SEEK_SET) != 0) {
        fclose(f);
        return { 0, 0 };
    }

    uint32_t rowLen_padded = (width*3 + 3) & (~3);
    std::unique_ptr<unsigned char[]> imageData {new unsigned char[rowLen_padded]};

    dataContainer.clear();
    dataContainer.assign(width * height, 0); // Pre-allocate to make random access easy

    // Fill the data container with 8-bit data taken from the image data:

    for (uint32_t y = 0; y < height; ++y) {
        if (fread(imageData.get(), sizeof(unsigned char), rowLen_padded, f) != rowLen_padded) {
            fclose(f);
            return { 0, 0 };
        }

        // BMP pixels are arranged in memory in the order (B, G, R):

        unsigned val = 0;

        for (uint32_t x = 0; x < width; ++x) {
            if (colorChannel == NNet::R) {
                val = imageData[x * 3 + 2]; // Red
            } else if (colorChannel == NNet::G) {
                val = imageData[x * 3 + 1]; // Green
            } else if (colorChannel == NNet::B) {
                val = imageData[x * 3 + 0]; // Blue
            } else if (colorChannel == NNet::BW) {
                // Rounds down:
                val = (unsigned)(0.3 * imageData[x*3 + 2] +   // Red
                                 0.6 * imageData[x*3 + 1] +   // Green
                                 0.1 * imageData[x*3 + 0]);   // Blue
            } else {
                err << "Error: unknown pixel conversion" << endl;
                throw exceptionImageFile();
            }

            // Convert the pixel from the range 0..256 to a smaller
            // range that we can input into the neural net:
            // Also we'll invert the rows so that the origin is the upper left at 0,0:

            dataContainer[flattenXY(x, (height - y) - 1, height)] = pixelToNetworkInputRange(val);
        }
    }

    fclose(f);

    return { width, height };
}