/* Main method to test math */ int main() { // Test matrix math struct Matrix a; //double valuesa[9] = { 5.0, -2.0, 1.0, 0.0, 3.0, -1.0, 2.0, 0.0, 7.0 }; double valuesa[16] = { 1.0, 3.0, -2.0, 1.0, 5.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -2.0, 2.0, -1.0, 0.0, 3.0 }; newMatrix(&a, valuesa, 4, 4); struct Matrix b; double valuesb[9] = { 1.0, 2.0, 3.0, 0.0, -4.0, 1.0, 0.0, 3.0, -1.0 }; newMatrix(&b, valuesb, 3, 3); struct Matrix cofa; matrixCofactor(&cofa, a); printf("A Cofactor=\n"); matrixToString(cofa); struct Matrix inva; matrixInverse(&inva, a); printf("A Inverse=\n"); matrixToString(inva); printf("A=\n"); matrixToString(a); printf("B=\n"); matrixToString(b); printf("A is %sa square matrix.\n", matrixIsSquare(a) ? "" : "not "); printf("B is %sa square matrix.\n", matrixIsSquare(b) ? "" : "not "); printf("The determinant of A is %f.\n", matrixDeterminant(a)); printf("A is %sunique.\n", matrixIsUnique(a) ? "" : "not "); printf("The determinant of B is %f.\n", matrixDeterminant(b)); printf("B is %sunique.\n", matrixIsUnique(b) ? "" : "not "); struct Matrix aplusb; matrixAdd(&aplusb, a, b); printf("A+B=\n"); matrixToString(aplusb); struct Matrix asubb; matrixSubtract(&asubb, a, b); printf("A-B=\n"); matrixToString(asubb); struct Matrix ascale; matrixScale(&ascale, a, 5); printf("5A=\n"); matrixToString(ascale); struct Matrix bscale; matrixScale(&bscale, b, 5); printf("5B=\n"); matrixToString(bscale); printf("A and B are %sthe same size.\n", matrixIsSameSize(a, b) ? "" : "not "); printf("A=\n"); matrixToString(a); printf("B=\n"); matrixToString(b); // Test 3D vector math }
void writeTMatrixList( std::ofstream *outFile, std::vector<MMatrix>& transformMatrices, bool inverse, float scaleFactor) { for( int matrixId = 0; matrixId < transformMatrices.size(); matrixId++) { MMatrix tm = transformMatrices[matrixId]; if( inverse ) tm = tm.inverse(); if( matrixId == 0) { *outFile << "\t\tray_transform " << matrixToString(tm) << "\n"; // normal transform } else{ *outFile << "\t\tray_mtransform " << matrixToString(tm) << "\n"; // motion transform } } }
static const VSFrameRef *VS_CC textGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { TextData *d = static_cast<TextData *>(*instanceData); if (activationReason == arInitial) { vsapi->requestFrameFilter(n, d->node, frameCtx); } else if (activationReason == arAllFramesReady) { const VSFrameRef *src = vsapi->getFrameFilter(n, d->node, frameCtx); const VSFormat *frame_format = vsapi->getFrameFormat(src); if ((frame_format->sampleType == stInteger && frame_format->bitsPerSample > 16) || (frame_format->sampleType == stFloat && frame_format->bitsPerSample != 32)) { vsapi->freeFrame(src); vsapi->setFilterError((d->instanceName + ": Only 8..16 bit integer and 32 bit float formats supported").c_str(), frameCtx); return nullptr; } VSFrameRef *dst = vsapi->copyFrame(src, core); if (d->filter == FILTER_FRAMENUM) { scrawl_text(std::to_string(n), d->alignment, dst, vsapi); } else if (d->filter == FILTER_FRAMEPROPS) { const VSMap *props = vsapi->getFramePropsRO(dst); int numKeys = vsapi->propNumKeys(props); int i; std::string text = "Frame properties:\n"; if (!d->props.empty()) { for (const auto &iter : d->props) { append_prop(text, iter, props, vsapi); } } else { for (i = 0; i < numKeys; i++) { const char *key = vsapi->propGetKey(props, i); append_prop(text, key, props, vsapi); } } scrawl_text(text, d->alignment, dst, vsapi); } else if (d->filter == FILTER_COREINFO) { const VSCoreInfo *ci = vsapi->getCoreInfo(core); std::string text; text.append(ci->versionString).append("\n"); text.append("Threads: ").append(std::to_string(ci->numThreads)).append("\n"); text.append("Maximum framebuffer cache size: ").append(std::to_string(ci->maxFramebufferSize)).append(" bytes\n"); text.append("Used framebuffer cache size: ").append(std::to_string(ci->usedFramebufferSize)).append(" bytes"); scrawl_text(text, d->alignment, dst, vsapi); } else if (d->filter == FILTER_CLIPINFO) { const VSMap *props = vsapi->getFramePropsRO(src); std::string text = "Clip info:\n"; if (d->vi->width) { text += "Width: " + std::to_string(vsapi->getFrameWidth(dst, 0)) + " px\n"; text += "Height: " + std::to_string(vsapi->getFrameHeight(dst, 0)) + " px\n"; } else { text += "Width: " + std::to_string(vsapi->getFrameWidth(dst, 0)) + " px (may vary)\n"; text += "Height: " + std::to_string(vsapi->getFrameHeight(dst, 0)) + " px (may vary)\n"; } int snerr, sderr; int sn = int64ToIntS(vsapi->propGetInt(props, "_SARNum", 0, &snerr)); int sd = int64ToIntS(vsapi->propGetInt(props, "_SARDen", 0, &sderr)); if (snerr || sderr) text += "Aspect ratio: Unknown\n"; else text += "Sample aspect ratio: " + std::to_string(sn) + ":" + std::to_string(sd) + "\n"; text += "Length: " + std::to_string(d->vi->numFrames) + " frames\n"; text += "Format name: " + std::string(frame_format->name) + (d->vi->format ? "\n" : " (may vary)\n"); text += "Color family: " + colorFamilyToString(frame_format->colorFamily) + "\n"; text += "Sample type: " + std::string(frame_format->sampleType == stInteger ? "Integer" : "Float") + "\n"; text += "Bits per sample: " + std::to_string(frame_format->bitsPerSample) + "\n"; text += "Subsampling Height/Width: " + std::to_string(1 << frame_format->subSamplingH) + "x/" + std::to_string(1 << frame_format->subSamplingW) + "x\n"; int err; int matrix = int64ToIntS(vsapi->propGetInt(props, "_Matrix", 0, &err)); if (err) matrix = -1; int primaries = int64ToIntS(vsapi->propGetInt(props, "_Primaries", 0, &err)); if (err) primaries = -1; int transfer = int64ToIntS(vsapi->propGetInt(props, "_Transfer", 0, &err)); if (err) transfer = -1; int range = int64ToIntS(vsapi->propGetInt(props, "_ColorRange", 0, &err)); if (err) range = -1; int location = int64ToIntS(vsapi->propGetInt(props, "_ChromaLocation", 0, &err)); if (err) location = -1; int field = int64ToIntS(vsapi->propGetInt(props, "_FieldBased", 0, &err)); if (err) field = -1; const char *picttype = vsapi->propGetData(props, "_PictType", 0, &err); text += "Matrix: " + matrixToString(matrix) + "\n"; text += "Primaries: " + primariesToString(primaries) + "\n"; text += "Transfer: " + transferToString(transfer) + "\n"; text += "Range: " + rangeToString(range) + "\n"; text += "Chroma Location: " + chromaLocationToString(location) + "\n"; text += "Field handling: " + fieldBasedToString(field) + "\n"; text += "Picture type: " + std::string(picttype ? picttype : "Unknown") + "\n"; if (d->vi->fpsNum && d->vi->fpsDen) { text += "Fps: " + std::to_string(d->vi->fpsNum) + "/" + std::to_string(d->vi->fpsDen) + " (" + std::to_string(static_cast<double>(d->vi->fpsNum) / d->vi->fpsDen) + ")\n"; } else { text += "Fps: Unknown\n"; } int fnerr, fderr; int fn = int64ToIntS(vsapi->propGetInt(props, "_DurationNum", 0, &fnerr)); int fd = int64ToIntS(vsapi->propGetInt(props, "_DurationDen", 0, &fderr)); if (fnerr || fderr) { text += "Frame duration: Unknown\n"; } else { text += "Frame duration: " + std::to_string(fn) + "/" + std::to_string(fd) + " (" + std::to_string(static_cast<double>(fn) / fd) + ")\n"; } scrawl_text(text, d->alignment, dst, vsapi); } else { scrawl_text(d->text, d->alignment, dst, vsapi); } vsapi->freeFrame(src); return dst; } return nullptr; }
/** * Solves a linear least squares problem to obtain a N degree polynomial that fits * the specified input data as nearly as possible. * * Returns true if a solution is found, false otherwise. * * The input consists of two vectors of data points X and Y with indices 0..m-1 * along with a weight vector W of the same size. * * The output is a vector B with indices 0..n that describes a polynomial * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. * * Accordingly, the weight vector W should be initialized by the caller with the * reciprocal square root of the variance of the error in each input data point. * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). * The weights express the relative importance of each data point. If the weights are * all 1, then the data points are considered to be of equal importance when fitting * the polynomial. It is a good idea to choose weights that diminish the importance * of data points that may have higher than usual error margins. * * Errors among data points are assumed to be independent. W is represented here * as a vector although in the literature it is typically taken to be a diagonal matrix. * * That is to say, the function that generated the input data can be approximated * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. * * The coefficient of determination (R^2) is also returned to describe the goodness * of fit of the model for the given data. It is a value between 0 and 1, where 1 * indicates perfect correspondence. * * This function first expands the X vector to a m by n matrix A such that * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then * multiplies it by w[i]./ * * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q * and an m by n upper triangular matrix R. Because R is upper triangular (lower * part is all zeroes), we can simplify the decomposition into an m by n matrix * Q1 and a n by n matrix R1 such that A = Q1 R1. * * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) * to find B. * * For efficiency, we lay out A and Q column-wise in memory because we frequently * operate on the column vectors. Conversely, we lay out R row-wise. * * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares * http://en.wikipedia.org/wiki/Gram-Schmidt */ static bool solveLeastSquares(const float* x, const float* y, const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { #if DEBUG_STRATEGY ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), vectorToString(x, m).c_str(), vectorToString(y, m).c_str(), vectorToString(w, m).c_str()); #endif // Expand the X vector to a matrix A, pre-multiplied by the weights. float a[n][m]; // column-major order for (uint32_t h = 0; h < m; h++) { a[0][h] = w[h]; for (uint32_t i = 1; i < n; i++) { a[i][h] = a[i - 1][h] * x[h]; } } #if DEBUG_STRATEGY ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); #endif // Apply the Gram-Schmidt process to A to obtain its QR decomposition. float q[n][m]; // orthonormal basis, column-major order float r[n][n]; // upper triangular matrix, row-major order for (uint32_t j = 0; j < n; j++) { for (uint32_t h = 0; h < m; h++) { q[j][h] = a[j][h]; } for (uint32_t i = 0; i < j; i++) { float dot = vectorDot(&q[j][0], &q[i][0], m); for (uint32_t h = 0; h < m; h++) { q[j][h] -= dot * q[i][h]; } } float norm = vectorNorm(&q[j][0], m); if (norm < 0.000001f) { // vectors are linearly dependent or zero so no solution #if DEBUG_STRATEGY ALOGD(" - no solution, norm=%f", norm); #endif return false; } float invNorm = 1.0f / norm; for (uint32_t h = 0; h < m; h++) { q[j][h] *= invNorm; } for (uint32_t i = 0; i < n; i++) { r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); } } #if DEBUG_STRATEGY ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str()); ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str()); // calculate QR, if we factored A correctly then QR should equal A float qr[n][m]; for (uint32_t h = 0; h < m; h++) { for (uint32_t i = 0; i < n; i++) { qr[i][h] = 0; for (uint32_t j = 0; j < n; j++) { qr[i][h] += q[j][h] * r[j][i]; } } } ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str()); #endif // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. // We just work from bottom-right to top-left calculating B's coefficients. float wy[m]; for (uint32_t h = 0; h < m; h++) { wy[h] = y[h] * w[h]; } for (uint32_t i = n; i != 0; ) { i--; outB[i] = vectorDot(&q[i][0], wy, m); for (uint32_t j = n - 1; j > i; j--) { outB[i] -= r[i][j] * outB[j]; } outB[i] /= r[i][i]; } #if DEBUG_STRATEGY ALOGD(" - b=%s", vectorToString(outB, n).c_str()); #endif // Calculate the coefficient of determination as 1 - (SSerr / SStot) where // SSerr is the residual sum of squares (variance of the error), // and SStot is the total sum of squares (variance of the data) where each // has been weighted. float ymean = 0; for (uint32_t h = 0; h < m; h++) { ymean += y[h]; } ymean /= m; float sserr = 0; float sstot = 0; for (uint32_t h = 0; h < m; h++) { float err = y[h] - outB[0]; float term = 1; for (uint32_t i = 1; i < n; i++) { term *= x[h]; err -= term * outB[i]; } sserr += w[h] * w[h] * err * err; float var = y[h] - ymean; sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; #if DEBUG_STRATEGY ALOGD(" - sserr=%f", sserr); ALOGD(" - sstot=%f", sstot); ALOGD(" - det=%f", *outDet); #endif return true; }