// Add multiple variables void drwnFrankCopula::setVariables(const drwnClique& c) { // Must have size 2, 3, or 4 (for now) DRWN_ASSERT_MSG(c.size() >= 2 && c.size() <= 4, "Archimedian copula must have size between 2 and 4") // Call set variables from parent drwnCdf::setVariables(c); // Calculate number of subsets of variables _numSubsets = 1 << size(); _partialDerivs = new range_type[_numSubsets << 1]; }
void drwnLBPFilterBank::filter(const cv::Mat& img, std::vector<cv::Mat>& response) const { // check input DRWN_ASSERT(img.data != NULL); if (response.empty()) { response.resize(this->numFilters()); } DRWN_ASSERT(response.size() == this->numFilters()); if (img.channels() != 1) { cv::Mat tmp(img.rows, img.cols, img.depth()); cv::cvtColor(img, tmp, CV_RGB2GRAY); return filter(tmp, response); } DRWN_ASSERT_MSG(img.depth() == CV_8U, "image must be 8-bit"); // allocate output channels as 32-bit floating point for (unsigned i = 0; i < response.size(); i++) { if ((response[i].rows == img.rows) && (response[i].cols == img.cols) && (response[i].depth() == CV_32F) && (response[i].channels() == 1)) { response[i].setTo(0.0f); } else { response[i] = cv::Mat::zeros(img.rows, img.cols, CV_32FC1); } } for (int y = 0; y < img.rows; y++) { const unsigned char *p = img.ptr<const unsigned char>(y); const unsigned char *p_prev = (y == 0) ? p : img.ptr<const unsigned char>(y - 1); const unsigned char *p_next = (y == img.rows - 1) ? p : img.ptr<const unsigned char>(y + 1); // 4-connected neighbourhood for (int x = 0; x < img.cols; x++) { if (p[x] > p_prev[x]) response[0].at<float>(y, x) = 1.0f; if ((x < img.cols - 1) && (p[x] > p[x + 1])) response[1].at<float>(y, x) = 1.0f; if (p[x] > p_next[x]) response[2].at<float>(y, x) = 1.0f; if ((x > 0) && (p[x] > p[x - 1])) response[3].at<float>(y, x) = 1.0f; } // 8-connected neighbourhood if (_b8Neighbourhood) { for (int x = 0; x < img.cols; x++) { if ((p[x] > p_prev[x]) && (x < img.cols - 1) && (p[x] > p[x + 1])) response[4].at<float>(y, x) = 1.0f; if ((x < img.cols - 1) && (p[x] > p[x + 1]) && (p[x] > p_next[x])) response[5].at<float>(y, x) = 1.0f; if ((p[x] > p_next[x]) && (x > 0) && (p[x] > p[x - 1])) response[6].at<float>(y, x) = 1.0f; if ((x > 0) && (p[x] > p[x - 1]) && (p[x] > p_prev[x])) response[7].at<float>(y, x) = 1.0f; } } } }
void drwnTextonFilterBank::filter(const cv::Mat& img, std::vector<cv::Mat>& response) const { // check input DRWN_ASSERT(img.data != NULL); if (response.empty()) { response.resize(NUM_FILTERS); } DRWN_ASSERT((int)response.size() == NUM_FILTERS); DRWN_ASSERT((img.channels() == 3) && (img.depth() == CV_8U)); for (int i = 0; i < NUM_FILTERS; i++) { if ((response[i].rows != img.rows) || (response[i].cols != img.cols)) { response[i] = cv::Mat(img.rows, img.cols, CV_32FC1); } DRWN_ASSERT((response[i].channels() == 1) && (response[i].depth() == CV_32F)); } int k = 0; // color convert DRWN_LOG_DEBUG("Color converting image..."); cv::Mat imgCIELab8U(img.rows, img.cols, CV_8UC3); cv::cvtColor(img, imgCIELab8U, CV_BGR2Lab); cv::Mat imgCIELab(img.rows, img.cols, CV_32FC3); imgCIELab8U.convertTo(imgCIELab, CV_32F, 1.0 / 255.0); cv::Mat greyImg(img.rows, img.cols, CV_32FC1); const int from_to[] = {0, 0}; cv::mixChannels(&imgCIELab, 1, &greyImg, 1, from_to, 1); // gaussian filter on all color channels DRWN_LOG_DEBUG("Generating gaussian filter responses..."); cv::Mat gImg32f(img.rows, img.cols, CV_32FC3); for (double sigma = 1.0; sigma <= 4.0; sigma *= 2.0) { const int h = 2 * (int)(_kappa * sigma) + 1; cv::GaussianBlur(imgCIELab, gImg32f, cv::Size(h, h), 0); cv::split(gImg32f, &response[k]); k += 3; } // derivatives of gaussians on just greyscale image DRWN_LOG_DEBUG("Generating derivative of gaussian filter responses..."); for (double sigma = 2.0; sigma <= 4.0; sigma *= 2.0) { // x-direction cv::Sobel(greyImg, response[k++], CV_32F, 1, 0, 1); cv::GaussianBlur(response[k - 1], response[k - 1], cv::Size(2 * (int)(_kappa * sigma) + 1, 2 * (int)(3.0 * _kappa * sigma) + 1), 0); // y-direction cv::Sobel(greyImg, response[k++], CV_32F, 0, 1, 1); cv::GaussianBlur(response[k - 1], response[k - 1], cv::Size(2 * (int)(3.0 * _kappa * sigma) + 1, 2 * (int)(_kappa * sigma) + 1), 0); } // laplacian of gaussian on just greyscale image DRWN_LOG_DEBUG("Generating laplacian of gaussian filter responses..."); cv::Mat tmpImg(img.rows, img.cols, CV_32FC1); for (double sigma = 1.0; sigma <= 8.0; sigma *= 2.0) { const int h = 2 * (int)(_kappa * sigma) + 1; cv::GaussianBlur(greyImg, tmpImg, cv::Size(h, h), 0); cv::Laplacian(tmpImg, response[k++], CV_32F, 3); } DRWN_ASSERT_MSG(k == NUM_FILTERS, k << " != " << NUM_FILTERS); }
double drwnAlphaExpansionInference::inference(drwnFullAssignment& mapAssignment) { // check factor graph is pairwise for (int i = 0; i < _graph.numFactors(); i++) { DRWN_ASSERT(_graph[i]->size() <= 2); } // initialize MAP assignment const drwnVarUniversePtr pUniverse(_graph.getUniverse()); const int nVariables = pUniverse->numVariables(); mapAssignment.resize(nVariables, 0); double bestEnergy = _graph.getEnergy(mapAssignment); const int maxAlpha = pUniverse->maxCardinality(); if (maxAlpha == 1) return bestEnergy; drwnFullAssignment assignment(mapAssignment); drwnMaxFlow *g = new drwnBKMaxFlow(nVariables); g->addNodes(nVariables); // iterate until convergence bool bChanged = true; int lastChanged = -1; int nonSubmodularMoves = 0; for (int nCycle = 0; bChanged; nCycle += 1) { bChanged = false; for (int alpha = 0; alpha < maxAlpha; alpha++) { if (alpha == lastChanged) break; // construct graph bool bNonSubmodularMove = false; g->reset(); for (int i = 0; i < _graph.numFactors(); i++) { const drwnTableFactor *phi = _graph[i]; if (phi->size() == 1) { // unary const int u = phi->varId(0); const double A = (*phi)[mapAssignment[u]]; const double B = (*phi)[alpha % pUniverse->varCardinality(u)]; g->addSourceEdge(u, A); g->addTargetEdge(u, B); } else if (phi->size() == 2) { // pairwise const int u = phi->varId(0); const int v = phi->varId(1); const int uAlpha = alpha % pUniverse->varCardinality(u); const int vAlpha = alpha % pUniverse->varCardinality(v); if ((uAlpha == mapAssignment[u]) && (vAlpha == mapAssignment[v])) continue; double A = (*phi)[phi->indexOf(v, mapAssignment[v], phi->indexOf(u, mapAssignment[u]))]; double B = (*phi)[phi->indexOf(v, vAlpha, phi->indexOf(u, mapAssignment[u]))]; double C = (*phi)[phi->indexOf(v, mapAssignment[v], phi->indexOf(u, uAlpha))]; double D = (*phi)[phi->indexOf(v, vAlpha, phi->indexOf(u, uAlpha))]; if (uAlpha == mapAssignment[u]) { g->addSourceEdge(v, A); g->addTargetEdge(v, B); } else if (vAlpha == mapAssignment[v]) { g->addSourceEdge(u, A); g->addTargetEdge(u, C); } else { // check for submodularity if (A + D > C + B) { // truncate non-submodular functions bNonSubmodularMove = true; const double delta = A + D - C - B; A -= delta / 3 - DRWN_EPSILON; C += delta / 3 + DRWN_EPSILON; B = A + D - C + DRWN_EPSILON; } g->addSourceEdge(u, A); g->addTargetEdge(u, D); B -= A; C -= D; B += DRWN_EPSILON; C += DRWN_EPSILON; DRWN_ASSERT_MSG(B + C >= 0, "B = " << B << ", C = " << C); if (B < 0) { g->addTargetEdge(v, B); g->addTargetEdge(u, -B); g->addEdge(v, u, 0.0, B + C); } else if (C < 0) { g->addTargetEdge(v, -C); g->addTargetEdge(u, C); g->addEdge(v, u, B + C, 0.0); } else { g->addEdge(v, u, B, C); } } } } // run inference if (bNonSubmodularMove) { nonSubmodularMoves += 1; } g->solve(); for (int i = 0; i < nVariables; i++) { assignment[i] = (g->inSetS(i) ? alpha % pUniverse->varCardinality(i) : mapAssignment[i]); } double e = _graph.getEnergy(assignment); DRWN_LOG_DEBUG("...cycle " << nCycle << ", iteration " << alpha << " has energy " << e); if (e < bestEnergy) { bestEnergy = e; mapAssignment = assignment; lastChanged = alpha; bChanged = true; } } } // free graph delete g; DRWN_LOG_DEBUG("..." << nonSubmodularMoves << " non-submodular moves"); return bestEnergy; }