Repository: opencv/opencv
File: modules/objdetect/src/qrcode_encoder.cpp (C++)

Code before:
            val = gfMul(val, pos) ^ C[j];
        }
        if (val == 0) {
            errLocs.push_back(static_cast<int>(codewords.size() - 1 - i));
        }
    }

    // Number of assumed errors does not match number of error locations
    if (errLocs.size() != L)
        return false;

    // Forney algorithm for error correction using syndromes and known error locations
    std::vector<uint8_t> errEval;
    gfPolyMul(C, syndromes, errEval);

    for (size_t i = 0; i < errLocs.size(); ++i) {
        uint8_t numenator = 0, denominator = 0;
        uint8_t X = gfPow(2, static_cast<int>(codewords.size() - 1 - errLocs[i]));
        uint8_t inv_X = gfDiv(1, X);

        for (size_t j = 0; j < L; ++j) {
            numenator = gfMul(numenator, inv_X) ^ errEval[L - 1 - j];
        }

        // Compute demoninator as a product of (1-X_i * X_k) for i != k
        // TODO: optimize, there is a dubplicated compute
        denominator = 1;
        for (size_t j = 0; j < errLocs.size(); ++j) {
            if (i == j)
                continue;
            uint8_t Xj = gfPow(2, static_cast<int>(codewords.size() - 1 - errLocs[j]));
            denominator = gfMul(denominator, 1 ^ gfMul(inv_X, Xj));
        }

        uint8_t errValue = gfDiv(numenator, denominator);
        codewords[errLocs[i]] ^= errValue;
    }

    // Trim error correction codewords
    codewords.resize(codewords.size() - numEcc);
    return true;
}

void QRCodeDecoderImpl::extractCodewords(Mat& source, std::vector<uint8_t>& codewords) {
    const VersionInfo& version_info = version_info_database[version];

    // Mask alignment markers
    std::vector<int> alignCenters;
    alignCenters.reserve(MAX_ALIGNMENT);
    for (int i = 0; i < MAX_ALIGNMENT && version_info.alignment_pattern[i]; i++)
        alignCenters.push_back(version_info.alignment_pattern[i]);

Review comment (performance):
There are more optimization opportunities in this code block related to `gfMul`.

However despite the problem it does not make any performance improvements as number of error locations is very very small.

Code after:
            val = gfMul(val, pos) ^ C[j];
        }
        if (val == 0) {
            errLocs.push_back(static_cast<int>(codewords.size() - 1 - i));
        }
    }

    // Number of assumed errors does not match number of error locations
    if (errLocs.size() != L)
        return false;

    // Forney algorithm for error correction using syndromes and known error locations
    std::vector<uint8_t> errEval;
    gfPolyMul(C, syndromes, errEval);

    // Precompute all X values for error locations to avoid duplicated computation
    std::vector<uint8_t> X_values(errLocs.size());
    for (size_t j = 0; j < errLocs.size(); ++j) {
        X_values[j] = gfPow(2, static_cast<int>(codewords.size() - 1 - errLocs[j]));
    }

    for (size_t i = 0; i < errLocs.size(); ++i) {
        uint8_t numenator = 0, denominator = 0;
        uint8_t X = X_values[i];
        uint8_t inv_X = gfDiv(1, X);

        for (size_t j = 0; j < L; ++j) {
            numenator = gfMul(numenator, inv_X) ^ errEval[L - 1 - j];
        }

        // Compute demoninator as a product of (1-X_i * X_k) for i != k
        denominator = 1;
        for (size_t j = 0; j < errLocs.size(); ++j) {
            if (i == j)
                continue;
            uint8_t Xj = X_values[j];
            denominator = gfMul(denominator, 1 ^ gfMul(inv_X, Xj));
        }

        uint8_t errValue = gfDiv(numenator, denominator);
        codewords[errLocs[i]] ^= errValue;
    }

    // Trim error correction codewords
    codewords.resize(codewords.size() - numEcc);
    return true;
}

void QRCodeDecoderImpl::extractCodewords(Mat& source, std::vector<uint8_t>& codewords) {
    const VersionInfo& version_info = version_info_database[version];