OpenCV+python:从 3.4.2 开始访问 HoughLines 累加器

Posted

技术标签:

【中文标题】OpenCV+python:从 3.4.2 开始访问 HoughLines 累加器【英文标题】:OpenCV+python: HoughLines accumulator access since 3.4.2 【发布时间】:2019-02-15 23:31:52 【问题描述】:

在 OpenCV 3.4.2 中,添加了为 HoughLines() 返回的每一行返回投票数(累加器值)的选项。在 python 中,这似乎受到支持,并在我的 OpenCV 安装的 python 文档字符串中读取:

"每条线由一个2或3元素向量(ρ, θ)或(ρ, θ,投票)。”

它也包含在docs 中(格式有些损坏)。 但是我无法在 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)

输出

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]]]

所需的行为是一个额外的列,其中包含每行收到的票数。与投票值相比,可以应用比标准阈值更高级的选项,因此它经常在 SE(here、here、here 和 here)上被请求和询问,有时相当于 HoughCircles ()。但是问题和答案(例如修改源和重新编译)都是在正式添加之前,因此不适用于当前情况。

【问题讨论】:

OpenCV 4.3.2 不存在... 4.0 的工作仍在进行中。最新版本是 3.4.3。 @Dan Mašek 编辑了错字。 4.3.2 -> 3.4.2. 查看the code,获得选票的方法(至少在C++ 中)是提供一个具有固定类型的OutputArray,特别是与CV_32FC3 等效的一个。例如,我认为这将是一个包装cv::Mat3f 的实例。在这一点上,我很怀疑你是否可以传递满足 Python 标准的东西,但我会尝试一下。 【参考方案1】:

从原版 OpenCV 3.4.3 开始,您无法在 Python 中使用此功能。

它在 C++ 中的工作原理

首先在implementation of 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");

然后我们可以在填充lines时看到implementation of HoughLinesStandard中使用的这个参数:

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]);

类似代码可见in HoughLinesSDiv

基于此,我们需要传入一个固定类型_OutputArray,并在3个通道中存储32位浮点数。如何制作固定类型(但不是固定大小,因为算法需要能够调整它的大小)_OutputArray?我们再来看看implementation:

泛型cv::Mat 不是固定类型,cv::UMat 也不是 一个选项是std::vector&lt;cv::Vec3f&gt; 另一个选项是cv::Mat3f(即cv::Matx&lt;_Tp, m, n&gt;

示例代码:

#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;

控制台输出:

[0, 2.3212879;
 1, 2.2340214;
 -1, 2.4609141]
[0, 2.3212879, 10;
 1, 2.2340214, 6;
 -1, 2.4609141, 6]

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;

总而言之,它尝试将lines 参数中传递的对象转换为cv::Mat,然后以cv::Mat 作为输出参数调用cv::HoughLines。 (如果失败,那么它会尝试使用 cv::UMat 做同样的事情)不幸的是,这意味着无法为 cv::HoughLines 提供固定类型 lines,因此从 3.4.3 开始,Python 无法访问此功能。


解决方案

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

快速破解

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

int type = CV_32FC3;

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

更好的补丁

添加一个可选的布尔参数return_votes,默认值为false。修改代码,使得当return_votestrue 时,type 被强制为CV_32FC3

Header:

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 );

Implementation:

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...

【讨论】:

感谢您的全面回答。是否旨在使此类功能无法从 python 访问,或者这是否可以被视为绑定或原始源代码中的错误? @user2246166 我猜这是一个疏忽,但为了确保这一点,我在相关的issue 中询问。【参考方案2】:

有一个新的python绑定(opencv 4.5.1)

文档:cv.HoughLinesWithAccumulator

【讨论】:

以上是关于OpenCV+python:从 3.4.2 开始访问 HoughLines 累加器的主要内容,如果未能解决你的问题,请参考以下文章

Python 大白从零开始 OpenCV 学习课-8. 频率域图像滤波(上)

如何从入门开始学习OpenCV?

Python 大白从零开始 OpenCV 学习课-5. 图像的几何变换

Python 大白从零开始 OpenCV 学习课-1.安装与环境配置

Python 大白从零开始 OpenCV 学习课-7. 空间域图像滤波

Python 大白从零开始 OpenCV 学习课-3.图像的创建与修改