使用OpenCV函数calcHist快速计算v-disparity

时间:2016-07-21 12:50:18

标签: python c++ opencv computer-vision

基于来自被动立体相机系统的视差矩阵,我需要计算用OpenCV检测障碍物的视差表示。

工作实施问题。问题是要快速做到......

(一)v-Disparity的参考:Labayrade,R。和Aubert,D。和Tarel,J.P。通过v-disparity表示在非平坦道路几何上立体视觉中的实时障碍物检测

简而言之,获得v-disparity(图1),就是分析视差矩阵的行(图2),并将结果表示为每个的直方图划过差异值。 u-disparity(图3)在视差矩阵的列上是相同的。 (所有数字均为假色。)

我在Python和C ++中实现了“相同”。 Python中的速度是可以接受的,但在C ++中,我得到的是u和v-disparity,时间大约是半秒(0.5秒)。

(1.编辑:由于单独的时间测量,只有u直方图的计算需要很长时间......)

这引出了以下问题:

  1. 是否可以避免用于直方图的逐行计算的循环?通过一次调用calcHist - 来自OpenCV的函数,是否有“技巧”?也许是尺寸?

  2. 它是否在C ++中编码错误且运行时问题与用于计算的循环无关?

  3. 谢谢,所有

    Python中的工作实现:

    #!/usr/bin/env python2
    #-*- coding: utf-8 -*-
    #
    # THIS SOURCE-CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    # IMPLIED. IN NO  EVENT WILL THE AUTHOR BE HELD LIABLE FOR ANY DAMAGES ARISING FROM
    # THE USE OF THIS SOURCE-CODE. USE AT YOUR OWN RISK.
    
    import cv2
    import numpy as np
    import time
    
    def draw_object(image, x, y, width=50, height=100):
        color = image[y, x]
        image[y-height:y, x-width//2:x+width//2] = color
    
    
    IMAGE_HEIGHT = 600
    IMAGE_WIDTH = 800
    
    while True:
    
        max_disp = 200
    
        # create fake disparity
        image = np.zeros((IMAGE_HEIGHT, IMAGE_WIDTH), np.uint8)
    
        for c in range(IMAGE_HEIGHT)[::-1]:
            image[c, ...] = int(float(c) / IMAGE_HEIGHT * max_disp)
    
        draw_object(image, 275, 175)
        draw_object(image, 300, 200)
        draw_object(image, 100, 350)
    
        # calculate v-disparity
        vhist_vis = np.zeros((IMAGE_HEIGHT, max_disp), np.float)
        for i in range(IMAGE_HEIGHT):
            vhist_vis[i, ...] = cv2.calcHist(images=[image[i, ...]], channels=[0], mask=None, histSize=[max_disp],
                                             ranges=[0, max_disp]).flatten() / float(IMAGE_HEIGHT)
    
    
        vhist_vis = np.array(vhist_vis * 255, np.uint8)
        vblack_mask = vhist_vis < 5
        vhist_vis = cv2.applyColorMap(vhist_vis, cv2.COLORMAP_JET)
        vhist_vis[vblack_mask] = 0
    
        # calculate u-disparity
        uhist_vis = np.zeros((max_disp, IMAGE_WIDTH), np.float)
        for i in range(IMAGE_WIDTH):
            uhist_vis[..., i] = cv2.calcHist(images=[image[..., i]], channels=[0], mask=None, histSize=[max_disp],
                                             ranges=[0, max_disp]).flatten() / float(IMAGE_WIDTH)
    
        uhist_vis = np.array(uhist_vis * 255, np.uint8)
        ublack_mask = uhist_vis < 5
        uhist_vis = cv2.applyColorMap(uhist_vis, cv2.COLORMAP_JET)
        uhist_vis[ublack_mask] = 0
    
    
        image = cv2.applyColorMap(image, cv2.COLORMAP_JET)
    
    
        cv2.imshow('image', image)
    
        cv2.imshow('vhist_vis', vhist_vis)
        cv2.imshow('uhist_vis', uhist_vis)
    
        cv2.imwrite('disparity_image.png', image)
        cv2.imwrite('v-disparity.png', vhist_vis)
        cv2.imwrite('u-disparity.png', uhist_vis)
    
    
        if chr(cv2.waitKey(0)&255) == 'q':
            break
    

    在C ++中实现工作:

    #include <iostream>
    #include <stdlib.h>
    
    #include <ctime>
    
    #include <opencv2/opencv.hpp>
    
    
    using namespace std;
    
    void draw_object(cv::Mat image, unsigned int x, unsigned int y, unsigned int width=50, unsigned int height=100)
    {
        image(cv::Range(y-height, y), cv::Range(x-width/2, x+width/2)) = image.at<unsigned char>(y, x);
    }
    
    
    int main()
    {
        unsigned int IMAGE_HEIGHT = 600;
        unsigned int IMAGE_WIDTH = 800;
        unsigned int MAX_DISP = 250;
        unsigned int CYCLE = 0;
    
        //setenv("QT_GRAPHICSSYSTEM", "native", 1);
    
    
        // === PREPERATIONS ==
        cv::Mat image = cv::Mat::zeros(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8U);
        cv::Mat uhist = cv::Mat::zeros(IMAGE_HEIGHT, MAX_DISP, CV_32F);
        cv::Mat vhist = cv::Mat::zeros(MAX_DISP, IMAGE_WIDTH, CV_32F);
    
        cv::Mat tmpImageMat, tmpHistMat;
    
        float value_ranges[] = {(float)0, (float)MAX_DISP};
        const float* hist_ranges[] = {value_ranges};
        int channels[] = {0};
        int histSize[] = {MAX_DISP};
    
    
        struct timespec start, finish;
        double elapsed;
    
        while(1)
        {
            CYCLE++;
    
            // === CLEANUP ==
            image = cv::Mat::zeros(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8U);
            uhist = cv::Mat::zeros(IMAGE_HEIGHT, MAX_DISP, CV_32F);
            vhist = cv::Mat::zeros(MAX_DISP, IMAGE_WIDTH, CV_32F);
    
            // === CREATE FAKE DISPARITY WITH OBJECTS ===
            for(int i = 0; i < IMAGE_HEIGHT; i++)
                image.row(i) = ((float)i / IMAGE_HEIGHT * MAX_DISP);
    
            draw_object(image, 200, 500);
            draw_object(image, 525 + CYCLE%100, 275);
            draw_object(image, 500, 300 + CYCLE%100);
    
            clock_gettime(CLOCK_MONOTONIC, &start);
    
            // === CALCULATE V-HIST ===
            for(int i = 0; i < IMAGE_HEIGHT; i++)
            {
                tmpImageMat = image.row(i);
                vhist.row(i).copyTo(tmpHistMat);
    
                cv::calcHist(&tmpImageMat, 1, channels, cv::Mat(), tmpHistMat, 1, histSize, hist_ranges, true, false);
    
                vhist.row(i) = tmpHistMat.t() / (float) IMAGE_HEIGHT;
            }
    
            clock_gettime(CLOCK_MONOTONIC, &finish);
            elapsed = (finish.tv_sec - start.tv_sec);
            elapsed += (finish.tv_nsec - start.tv_nsec) * 1e-9;
            cout << "V-HIST-TIME: " << elapsed << endl;
    
            clock_gettime(CLOCK_MONOTONIC, &start);
    
            // === CALCULATE U-HIST ===
            for(int i = 0; i < IMAGE_WIDTH; i++)
            {
                tmpImageMat = image.col(i);
                uhist.col(i).copyTo(tmpHistMat);
    
                cv::calcHist(&tmpImageMat, 1, channels, cv::Mat(), tmpHistMat, 1, histSize, hist_ranges, true, false);
    
                uhist.col(i) = tmpHistMat / (float) IMAGE_WIDTH;
            }
    
            clock_gettime(CLOCK_MONOTONIC, &finish);
            elapsed = (finish.tv_sec - start.tv_sec);
            elapsed += (finish.tv_nsec - start.tv_nsec) * 1e-9;
            cout << "U-HIST-TIME: " << elapsed << endl;
    
            // === PREPARE AND SHOW RESULTS ===
    
            uhist.convertTo(uhist, CV_8U, 255);
            cv::applyColorMap(uhist, uhist, cv::COLORMAP_JET);
    
            vhist.convertTo(vhist, CV_8U, 255);
            cv::applyColorMap(vhist, vhist, cv::COLORMAP_JET);
    
            cv::imshow("image", image);
            cv::imshow("uhist", uhist);
            cv::imshow("vhist", vhist);
    
    
    
            if ((cv::waitKey(1)&255) == 'q')
                break;
        }
    
        return 0;
    }
    

    enter image description here 图1:v-disparity

    fake disparity matrix 图2:伪差异矩阵

    enter image description here 图3:u-disparity

    1. 编辑:
      • u-和v-disparity的正确名称以及c ++示例中的单独时间测量
      • 小错字

2 个答案:

答案 0 :(得分:0)

今天我有可能重新调查这个问题。记住Mat - 结构的OpenCV基础知识(1)以及只有一次计算花费大量时间的事实,我得到了解决方案。

在OpenCV中,行指针可以到达图像的每一行。对于迭代列(在u-disparity计算中完成)我怀疑,OpenCV需要解析每个行指针+列偏移量以构建直方图。

以某种方式更改代码,OpenCV能够使用行指针,为我解决了这个问题。

            | old code [s] | changed [s]
------------+--------------+-------------
V-HIST-TIME | 0.00351909   | 0.00334152
U-HIST-TIME | 0.600039     | 0.00449285

因此对于u-hist-loop我转换图像并在循环后反转操作。现在可以通过行指针完成计算的直线访问。

更改了代码行:

        // === CALCULATE U-HIST ===
        image = image.t();
        for(int i = 0; i < IMAGE_WIDTH; i++)
        {
            tmpImageMat = image.row(i);
            uhist.col(i).copyTo(tmpHistMat);

            cv::calcHist(&tmpImageMat, 1, channels, cv::Mat(), tmpHistMat, 1, histSize, hist_ranges, true, false);

            uhist.col(i) = tmpHistMat / (float) IMAGE_WIDTH;
        }
        image = image.t();

最后我的第二个问题生效,运行时问题不属于循环。小于5毫秒的时间(现在)足够快。

答案 1 :(得分:0)

非常好的代码,非常具有说明性。它帮助我理解了你的差距。但是,您的C / C ++代码已损坏。我用这段代码修理了他:

cv::Mat uhist = cv::Mat::zeros(MAX_DISP, IMAGE_WIDTH, CV_32F);
cv::Mat vhist = cv::Mat::zeros(IMAGE_WIDTH, MAX_DISP, CV_32F);