OpenCV + python:自3.4.2起HoughLines累加器访问

use*_*166 5 python opencv hough-transform

在OpenCV 3.4.2中,添加了返回HoughLines()返回的每一行的投票数(累加器值)的选项.在python中,似乎支持以及在我的OpenCV安装的python docstring中读取:

"每条线由2或3个元素向量(ρ,θ)或(ρ,θ,votes)表示."

它也包含在文档中(有一些破碎的格式). 但是我找不到在python中返回3元素选项(ρ,θ,votes)的方法. 以下是演示此问题的代码:

import numpy as np
import cv2
print('OpenCV should be at least 3.4.2 to test: ', cv2.__version__)
image = np.eye(10, dtype='uint8')
lines = cv2.HoughLines(image, 1, np.pi/180, 5)
print('(number of lines, 1, output vector dimension): ', lines.shape)
print(lines)
Run Code Online (Sandbox Code Playgroud)

输出

OpenCV should be at least 3.4.2 to test:  3.4.2
(number of lines, 1, output vector dimension):  (3, 1, 2)
[[[ 0.         2.3212879]]

 [[ 1.         2.2340214]]

 [[-1.         2.4609141]]]
Run Code Online (Sandbox Code Playgroud)

所需的行为是一个额外的列,每行收到的投票数量.使用投票值可以应用比标准阈值更高级的选项,因此它经常被请求并询问SE(这里,这里,这里这里),有时等效于HoughCircles().但是,问题和答案(例如修改源代码和重新编译)都是在正式添加之前,因此不适用于当前情况.

Dan*_*šek 11

从vanilla OpenCV 3.4.3开始,您无法使用Python的此功能.

它在C++中的工作原理

首先在实现中HoughLines,我们可以看到选择输出数组类型的代码lines:

int type = CV_32FC2;
if (lines.fixedType())
{
    type = lines.type();
    CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Wrong type of output lines");
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以看到这个参数用于填充时的实现HoughLinesStandardlines:

if (type == CV_32FC2)
{
    _lines.at<Vec2f>(i) = Vec2f(line.rho, line.angle);
}
else
{
    CV_DbgAssert(type == CV_32FC3);
    _lines.at<Vec3f>(i) = Vec3f(line.rho, line.angle, (float)accum[idx]);
}
Run Code Online (Sandbox Code Playgroud)

类似的代码可以看出HoughLinesSDiv.

在此基础上,我们需要在通过_OutputArray固定式,并将其存储在3个信道32bit的浮动.如何制作固定类型(但不是固定大小,因为算法需要能够调整大小)_OutputArray?让我们再看一下实现:

  • 泛型cv::Mat不是固定类型,也不是cv::UMat
  • 一种选择是 std::vector<cv::Vec3f>
  • 另一个选择是cv::Mat3f(那是一个cv::Matx<_Tp, m, n>)

示例代码:

#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat image(cv::Mat::eye(10, 10, CV_8UC1) * 255);

    cv::Mat2f lines2;
    cv::HoughLines(image, lines2, 1, CV_PI / 180, 4); // runs the actual detection
    std::cout << lines2 << "\n";

    cv::Mat3f lines3;;
    cv::HoughLines(image, lines3, 1, CV_PI / 180, 4); // runs the actual detection
    std::cout << lines3 << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

控制台输出:

[0, 2.3212879;
 1, 2.2340214;
 -1, 2.4609141]
[0, 2.3212879, 10;
 1, 2.2340214, 6;
 -1, 2.4609141, 6]
Run Code Online (Sandbox Code Playgroud)

Python包装器的工作原理

让我们看看包装HoughLines函数的自动生成代码:

static PyObject* pyopencv_cv_HoughLines(PyObject* , PyObject* args, PyObject* kw)
{
    using namespace cv;

    {
    PyObject* pyobj_image = NULL;
    Mat image;
    PyObject* pyobj_lines = NULL;
    Mat lines;
    double rho=0;
    double theta=0;
    int threshold=0;
    double srn=0;
    double stn=0;
    double min_theta=0;
    double max_theta=CV_PI;

    const char* keywords[] = { "image", "rho", "theta", "threshold", "lines", "srn", "stn", "min_theta", "max_theta", NULL };
    if( PyArg_ParseTupleAndKeywords(args, kw, "Oddi|Odddd:HoughLines", (char**)keywords, &pyobj_image, &rho, &theta, &threshold, &pyobj_lines, &srn, &stn, &min_theta, &max_theta) &&
        pyopencv_to(pyobj_image, image, ArgInfo("image", 0)) &&
        pyopencv_to(pyobj_lines, lines, ArgInfo("lines", 1)) )
    {
        ERRWRAP2(cv::HoughLines(image, lines, rho, theta, threshold, srn, stn, min_theta, max_theta));
        return pyopencv_from(lines);
    }
    }
    PyErr_Clear();

    // Similar snippet handling UMat...

    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

总结一下,它尝试将lines参数中传递的对象转换为a cv::Mat,然后cv::HoughLines使用cv::Matas作为输出参数进行调用.(如果失败了,那么它会尝试同样的事情cv::UMat)不幸的是,这意味着无法提供cv::HoughLines固定类型lines,因此从3.4.3开始,这个功能无法从Python中获取.


解决方案

据我所知,唯一的解决方案涉及修改OpenCV源代码和重建.

快速黑客

这很简单,编辑实现cv::HoughLines并将默认类型更改为CV_32FC3:

int type = CV_32FC3;
Run Code Online (Sandbox Code Playgroud)

但是,这意味着您将始终获得投票(这也意味着OpenCL优化,如果存在,将不会被使用).

更好的补丁

添加return_votes具有默认值的可选布尔参数false.修改,这样当代码return_votestrue,将type被强制CV_32FC3.

标题:

CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines,
                              double rho, double theta, int threshold,
                              double srn = 0, double stn = 0,
                              double min_theta = 0, double max_theta = CV_PI,
                              bool return_votes = false );
Run Code Online (Sandbox Code Playgroud)

实施:

void HoughLines( InputArray _image, OutputArray lines,
                 double rho, double theta, int threshold,
                 double srn, double stn, double min_theta, double max_theta,
                 bool return_votes )
{
    CV_INSTRUMENT_REGION()

    int type = CV_32FC2;
    if (return_votes)
    {
         type = CV_32FC3;
    }
    else if (lines.fixedType())
    {
        type = lines.type();
        CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Wrong type of output lines");
    }
    // the rest...
Run Code Online (Sandbox Code Playgroud)