首页 > 解决方案 > 高效的livewire算法

问题描述

我使用的是这里给出的 livewire 算法。算法给出的结果如下:

结果

但真正的问题是它对于大图像非常慢。我需要处理代码的图像是 RGB 4032 × 3024。如此大的图像大大降低了代码的速度。我知道那里有有效的代码可以有效地执行此过程。谁能指出我正确的方向?这是我的 OpenCV 代码

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#define CV_BGR2GRAY cv::COLOR_BGRA2GRAY
using namespace cv;

const double inf = 0x3f3f3f3f3f;

Mat img, img_gray, img_value, fz, fg, I, pre, cost, vis, G, img_draw, in_que, skip, img_canny;
bool g_flag;

Point start;

void Mat_init(){
    I.create(img.rows, img.cols, CV_64FC2);
    G.create(img.rows, img.cols, CV_64FC1);
    fg.create(img.rows, img.cols, CV_64FC1);
    pre.create(img.rows, img.cols, CV_32SC2);
    cost.create(img.rows, img.cols, CV_64FC1);
    vis.create(img.rows, img.cols, CV_8UC1);
    fz.create(img.rows, img.cols, CV_64FC1);
    in_que.create(img.rows, img.cols, CV_8UC1);
    skip.create(img.rows, img.cols, CV_8UC1);
}

double getcost(Point p, Point q, bool flag){
    double Ixp = I.at<Vec2d>(p.y, p.x)[0];
    double Iyp = I.at<Vec2d>(p.y, p.x)[1];
    double Ixq = I.at<Vec2d>(q.y, q.x)[0];
    double Iyq = I.at<Vec2d>(q.y, q.x)[1];
    double fZ = 0.0, fG = 0.0, fD = 0.0;
    fZ = fz.at<uchar>(q.y, q.x);
    fG = fg.at<double>(q.y, q.x);
    double judge = 0;
    judge = Iyp * (q.x - p.x) + (-Ixp) * (q.y - p.y);
    double dp = 0.0, dq = 0.0;
    // q - p
    if (judge >= 0){
        dp = Iyp * (q.x - p.x) + (-Ixp) * (q.y - p.y);
        dq = (q.x - p.x) * Iyq + (q.y - p.y) * (-Ixq);
    }
    // p - q
    else{
        dp = Iyp * (p.x - q.x) + (-Ixp) * (p.y - q.y);
        dq = (p.x - q.x) * Iyq + (p.y - q.y) * (-Ixq);
    }
    if (!flag){
        dp /= sqrt(2);
        dq /= sqrt(2);
    }
    double pi = acos(-1.0);
    fD = (acos(dp) + acos(dq)) / pi;
    if (flag)
        fG /= sqrt(2); // vertical or horizontal neighbor
    double ans = 0.43 * fZ + 0.43 * fD + 0.14 * fG;
    return ans;
}

struct P{
    double first;
    Point second;
    P(){}
    P(double a,Point b){
        first = a;
        second = b;
    }
    bool operator > (const P &b) const{
        return first > b.first;
    }
    bool operator < (const P &b) const{
        return first < b.first;
    }
};

void find_min_path(Point start){
    int dir_x[] = {1, 0, -1, 0, 1, 1, -1, -1};
    int dir_y[] = {0, 1, 0, -1, 1, -1, 1, -1};
    vis.setTo(0);
    cost.setTo(inf);
    in_que.setTo(0);
    skip.setTo(0);
    cost.at<double>(start.y, start.x) = 0;
    in_que.at<uchar>(start.y, start.x) = 1;
    std::priority_queue < P, std::vector<P>, std::greater<P> > que;
    que.push(P(0, start));
    while (!que.empty()){
        P cur = que.top();
        que.pop();
        Point p = cur.second;
        in_que.at<uchar>(p.y, p.x) = 0;
        if (skip.at<uchar>(p.y, p.x) == 1)
            continue;
        vis.at<uchar>(p.y, p.x) = 1;
        for (int i = 0; i < 8; i++){
            int tx = p.x + dir_x[i];
            int ty = p.y + dir_y[i];
            if (tx < 0 || tx >= img.cols || ty < 0 || ty >= img.rows)
                continue;
            if (vis.at<uchar>(ty, tx) == 1)
                continue;
            Point q = Point(tx, ty);
            double tmp;
            if (i <= 3){
                tmp = cost.at<double>(p.y, p.x) + getcost(p, q, true);
            }
            else{
                tmp = cost.at<double>(p.y, p.x) + getcost(p, q, false);
            }
            if (in_que.at<uchar>(q.y, q.x) == 1 && tmp < cost.at<double>(q.y, q.x)){
                skip.at<uchar>(q.y, q.x) = 1;
                continue;
            }

            if (in_que.at<uchar>(q.y, q.x) == 0){
                cost.at<double>(q.y, q.x) = tmp;
                pre.at<Vec2i>(q.y, q.x)[0] = p.x;
                pre.at<Vec2i>(q.y, q.x)[1] = p.y;
                in_que.at<uchar>(q.y, q.x) = 1;
                que.push(P(cost.at<double>(q.y, q.x), q));
            }
        }
    }
}

void onMouse(int event, int x, int y, int flags, void *param){
    if (event == EVENT_LBUTTONDOWN){
        start = Point(x, y);
        g_flag = true;
        find_min_path(start);
        img.copyTo(img_draw);
        imshow("example", img_draw);
    }
    else if (event == EVENT_MOUSEMOVE && g_flag){
        img.copyTo(img_draw);
        Point cur = Point(x, y);
        Point tmp;
        while (cur != start){
            tmp = Point(pre.at<Vec2i>(cur.y, cur.x)[0], pre.at<Vec2i>(cur.y, cur.x)[1]);
            line(img_draw, cur, tmp, Scalar(0, 255, 0), 2);
            if (tmp == start) break;
            cur = tmp;
        }
        imshow("example", img_draw);
    }
    else if (event == EVENT_LBUTTONUP){
        g_flag = false;
        img.copyTo(img_draw);
        imshow("example", img_draw);
    }
}

int main(){
    std::string filepath = "/Users/vedanshu/Desktop/test.png";
    namedWindow("example");
    img = imread(filepath);
    Mat_init();
    cvtColor(img, img_gray, CV_BGR2GRAY);   // Convert the image to grayscale (using the function cvtColor)
    img_gray.copyTo(img_value);
    GaussianBlur(img_value, img_value, Size(3, 3), 0, 0, BORDER_DEFAULT);   // First, we blur the image with a filter of kernel size 3
    Canny(img_gray, img_canny, 50, 100);    // Second, we apply the OpenCV function Canny

    //Calculating laplacian zero-crossing binary feature, fz
    for (int i = 0; i < img.rows; i++){
        for (int j = 0; j < img.cols; j++){
            if (img_canny.at<uchar>(i, j) == 255) fz.at<uchar>(i, j) = 0;
            else    fz.at<uchar>(i, j) = 1;
        }
    }
    //Calculating Ix unit vector
    for (int i = 0; i < img.rows; i++){
        for (int j = 0; j < img.cols - 1; j++){
            I.at<Vec2d>(i, j)[0] = (img_value.at<uchar>(i, j + 1) - img_value.at<uchar>(i, j)) / 255.0;
        }
        I.at<Vec2d>(i, img.cols - 1)[0] = I.at<Vec2d>(i, img.cols - 2)[0];
    }
    //Calculating Iy unit vector
    for (int j = 0; j < img.cols; j++){
        for (int i = 0; i < img.rows - 1; i++){
            I.at<Vec2d>(i, j)[1] = (img_value.at<uchar>(i + 1, j) - img_value.at<uchar>(i, j)) / 255.0;
        }
        I.at<Vec2d>(img.rows - 1, j)[1] = I.at<Vec2d>(img.rows - 2, j)[1];
    }

    double max_G = 0.0;
    // If Ix and Iy represent the partials of an image I in x and y respectively, then the gradient magnitude G is approximated with
    // G = sqrt(Ix^2 + Iy^2)
    for (int i = 0; i < I.rows; i++){
        for (int j = 0; j < I.cols; j++){
            G.at<double>(i, j) = sqrt(I.at<Vec2d>(i, j)[0] * I.at<Vec2d>(i, j)[0] + I.at<Vec2d>(i, j)[1] * I.at<Vec2d>(i, j)[1]);
            max_G = max(max_G, G.at<double>(i, j));
        }
    }
    //Calculating the gradient component function
    for (int i = 0; i < fg.rows; i++){
        for (int j = 0; j < fg.cols; j++){
            fg.at<double>(i, j) = 1.0 - G.at<double>(i, j) / max_G;
        }
    }
    std::cout << "calculate of fz and fg completed!" << std::endl;
    setMouseCallback("example", onMouse, 0);
    imshow("example", img);
    waitKey(0);
}

标签: imagealgorithmopencvimage-processing

解决方案


推荐阅读