Kernel-based Hough transform (KHT)移植

Kernel-based Hough transform (KHT)移植

本周发现了一篇讲解可以很大程度加快霍夫变换的论文,并且已经有实现好的例程了,所以想试下看以后能不能用的上,算法名字叫Kernel-based Hough transform (KHT)。暂时还没看懂,不过经过试验,在我电脑上(i3-2310M)对于2560x1920的图像找出直线大约需要70ms,对比下一直使用的OpenCV的标准算法大约需要200ms,release版本只需要20ms,OpenCV release版本需要110ms

简介:

Fernandes and Oliveira1suggested an improved voting scheme for the Hough transform that allows a software implementation to achieve real-time performance even on relatively large images (e.g., 1280×960). The Kernel-based Hough transform uses the same (r,\theta ) parameterization proposed by Duda and Hart but operates on clusters of approximately collinear pixels. For each cluster, votes are cast using an oriented elliptical-Gaussian kernel that models the uncertainty associated with the best-fitting line with respect to the corresponding cluster. The approach not only significantly improves the performance of the voting scheme, but also produces a much cleaner accumulator and makes the transform more robust to the detection of spurious lines.2

该项目在SourceForge中公布源代码
下载链接:
http://iweb.dl.sourceforge.net/project/khtsandbox/khtsandbox/KHT%20Sandbox%201.0.2/kht_sandbox-1.0.2-source.zip
http://kht-sandbox.soft112.com/
下载解压后共三个文件夹

  • kht_source中是kst算法的源码
  • matlab中是matlab使用示例
  • sample_app中是使用示例

sample_app中的工程可以用vs2010打开转换下,sample_app_vc++9.sln和sample_app_vc++8.sln都可以转换成功(我只有vs2010,更低版本的应该也可以)
但工程属性需要改一下

  • 常规->输出目录$(SolutionDir)$(Configuration)\
  • 常规->中间目录$(Configuration)$\
  • 链接器->输出文件$(OutDir)$(TargetName)$(TargetExt)
  • 切换到Debug状态时还要再改一遍

这里写图片描述
默认是Release 状态, Ctrl+F5运行下,结果很好:图像大小为800x800左右,帧率依次为25,28,27,30,34,40,35,40

这里写图片描述
这里写图片描述
这里写图片描述

分析程序:

测试程序是用OpenIL(不过现在又叫DevIL,不懂)来读取图像的,原图是单色位图,但是读进来后一个像素还是一个字节的,我用一张小图片测试了一下,像素在数组中的位置还是从左到右,从上到下的。和OpenCV一样。所有图像读取后都存到images_list中,最重要的变换函数是

kht( lines, image->pixels_copy, image->width, image->height, 10, 2.0, 0.5, 0.002, 2 );

不过貌似这个函数会更改输入图像,全部置0,所以需要提前备份一份。
得到的每条直线的rho和theta,theta不是弧度制的,所以后面有一句将角度转成弧度制。

double theta = line.theta * deg_to_rad;

需要注意的是:求得的rho和theta是以图像中心为坐标原点的,用OpenCV画直线时需要转化一下。
画直线是用OpenGL和Glut实现的,OpenGL也是以图像中心为坐标原点的,所以最左下角的点的坐标为(-w/2,-h/2), 最右上角的点的坐标为(w/2,h/2)。

glBegin( GL_LINES ); //就是开始画直线了
glVertex2d( -aux, (line.rho + aux * cos_theta) * one_div_sin_theta );//给定第一个端点
glVertex2d( aux, (line.rho - aux * cos_theta) * one_div_sin_theta );//给定第二个端点

画线这一段原理是利用式1,直线上的所有点(x,y)都满足式1,解方程,再将x=-w/2和x=w/2带入求得两个端点。

xcosθ+ysinθ=ρ

y=ρxcosθsinθ

w2=w2,x1=w2,y1=ρ+w2cosθsinθ

x2=w2,y1=ρw2cosθsinθ

移植到自己程序中并用OpenCV画出检测出的直线

移植到自己程序中只需将kht_source文件夹复制到自己程序文件夹内,并添加到工程中,在主函数前面包括进kht.h。

#include "./kht_source/kht.h"

复制要处理的图像数据,调用kht函数就可以了

Mat img_copy = img.clone();
static lines_list_t lines;
kht( lines, img_copy.data, img.cols, img.rows, 10, 2.0, 0.5, 0.002, 2 );

绘制直线就比较麻烦了,OpenCV的坐标原点是左上角,要做坐标变换。
设OpenGL中点的坐标为(x,y),OpenCV中点的坐标为(u,v),则:

u=x+w/2,v=h/2y

但测试时发现还是出错 #待解决,程序中实际情况是
u=x+w/2,v=h/2+y

整体测试程序见附录,但是测试building_binary.bmp时出现问题,该图画出的直线和原来的示例不同。 #待解决
这里写图片描述

附录 KHT+OpenCV测试程序

// HoughLineTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <time.h>
#include "./kht_source/kht.h"
#include <opencv2/opencv.hpp>
using namespace cv;
#define mymin(x,y) (x<y?x:y)
#ifndef PI
#define PI 3.14
#endif 
void drawline(Mat& imgs,vector<Point2f>& linesl);
void drawline(Mat& imgs,lines_list_t& lines);
int _tmain(int argc, _TCHAR* argv[])
{
    // Load input binary images.
    static const size_t images_count = 8;
    static const char *filenames[images_count]       = {"./images/chess_binary.bmp", "./images/road_binary.bmp", "./images/wall_binary.bmp", "./images/board_binary.bmp", "./images/church_binary.bmp", "./images/building_binary.bmp", "./images/beach_binary.bmp", "./images/simple_binary.bmp" };
    static const size_t relevant_lines[images_count] = {25,                          15,                         36,                         38,                          40,                           19,                             19,                          8                            };
    int test_flag = 0;
    while(test_flag)
    {
        Mat img = imread(filenames[0],0);
        Mat img_copy = img.clone();
        static lines_list_t lines;
        //vector<Point2f> lines;
        time_t time_start,time_stop;
        time_start = clock();
        kht( lines, img_copy.data, img.cols, img.rows, 10, 2.0, 0.5, 0.002, 2 );
        //HoughLines(img_copy, lines, 1, CV_PI/180, 140, 0, 0 );
        time_stop = clock();
        std::cout<<time_stop-time_start<<std::endl;
    }
    for (size_t i=0; i!=images_count; ++i)
    {
        Mat img = imread(filenames[i],0);
        if(img.channels()==1)
        {
            Mat img_copy = img.clone();

            static lines_list_t lines;
            kht( lines, img_copy.data, img.cols, img.rows, 10, 2.0, 0.5, 0.002, 2 );
//          vector<Point2f> lines;
//           HoughLines(img_copy, lines, 1, CV_PI/180, 130, 0, 0 );
            drawline(img,lines);
        }
    }
    return 0;
}
void drawline(Mat& imgs,vector<Point2f>& lines)
{
    Mat imgl;
    cvtColor(imgs,imgl,CV_GRAY2BGR);
    for( size_t i=0,linenum=mymin(25,lines.size());i<linenum; i++ )
    {

        float rho = lines[i].x, theta = lines[i].y;

        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 2000*(-b));
        pt1.y = cvRound(y0 + 2000*(a));
        pt2.x = cvRound(x0 - 2000*(-b));
        pt2.y = cvRound(y0 - 2000*(a));
        cv::line( imgl, pt1, pt2, cvScalar(0,0,255), 1, CV_AA);
    }   
    imshow("Horize HoughLines",imgl);
    waitKey();
}
void drawline(Mat& imgs,lines_list_t& lines)
{
    Mat imgl;
    cvtColor(imgs,imgl,CV_GRAY2BGR);
    if(lines.size())
    {
        for( size_t i=0,linenum=mymin(25,lines.size());i<linenum; i++ )
        {
            line_t &line = lines[i];
            Point pt1,pt2;
            if(line.theta != 0.0)
            { 
                int w2 = imgl.cols/2;
                int h2 = imgl.rows/2;
                static const double deg_to_rad = PI/ 180.0;
                double theta = line.theta * deg_to_rad;
                double rho = line.rho;
                double cos_theta = cos( theta );
                double one_div_sin_theta = 1 / sin( theta );
                pt1.x = 0;
                pt1.y = h2 + (line.rho + w2 * cos_theta) * one_div_sin_theta ;
                pt2.x = w2+w2;
                pt2.y = h2 + (line.rho - w2 * cos_theta) * one_div_sin_theta ;
                cv::line( imgl, pt1, pt2, cvScalar(0,0,250), 1, CV_AA); 
            }
            else
            {
                int w2 = imgl.cols/2;
                int h2 = imgl.rows/2;
                pt1.x = w2 + line.rho;
                pt1.y = 0;
                pt2.x = w2 + line.rho;
                pt2.y = h2+h2;
                cv::line( imgl, pt1, pt2, cvScalar(0,0,250), 1, CV_AA); 
            }

        }   
    }
    imshow("Horize HoughLines",imgl);
    waitKey();
}


  1. [1]:Fernandes L A F, Oliveira M M. Real-time line detection through an improved Hough transform voting scheme[J]. Pattern Recognition, 2008, 41(1):299-314.
    [2]: https://en.wikipedia.org/wiki/Hough_transform
  2. [1]:Fernandes L A F, Oliveira M M. Real-time line detection through an improved Hough transform voting scheme[J]. Pattern Recognition, 2008, 41(1):299-314.
    [2]: https://en.wikipedia.org/wiki/Hough_transform
### Deep Hough Transform 在车道线检测中的实现方法 Deep Hough Transform 是一种结合传统霍夫变换 (Hough Transform) 和现代深度学习的技术,用于解决计算机视觉领域中的几何形状检测问题。在车道线检测的应用场景下,这种方法通过神经网络预测参数空间的概率分布图,并将其映射到霍夫空间以完成高效的车道线拟合。 #### 方法概述 Deep Hough Transform 的核心思想在于利用卷积神经网络 (CNN) 对输入图像进行端到端的学习,从而生成一组描述车道线特性的概率分布图。这些分布图随后被转换至极坐标系下的霍夫空间,在该空间中执行峰值检测操作来定位潜在的车道线位置[^1]。 具体而言,模型架构通常由以下几个部分组成: 1. **特征提取模块**: 使用预训练好的 CNN 或自定义设计的编码器从原始图片中抽取高层次语义信息; 2. **回归分支**: 基于上述特征向量估计每条候选直线对应的斜率与截距值; 3. **投票机制**: 将所有可能解投影回霍夫域形成累积直方图以便后续分析处理; 4. **后置优化阶段**: 应用卡尔曼滤波(Kalman Filtering)[^3]或其他时间序列算法平滑轨迹变化并剔除异常干扰项。 以下是基于 PyTorch 实现的一个简化版框架示例: ```python import torch from torchvision import models class DHTRNet(torch.nn.Module): def __init__(self, num_classes=2): # Assuming binary classification for lanes super(DHTRNet,self).__init__() resnet = models.resnet18(pretrained=True) layers=list(resnet.children())[:-2] self.encoder=torch.nn.Sequential(*layers) self.regressor=torch.nn.Linear(512*7*7,num_classes*2)# Output rho & theta pairs def forward(self,x): features=self.encoder(x).view(-1,512*7*7) params=self.regressor(features) return params.reshape((-1,2)) ``` 此代码片段仅展示了一个基础版本的网络结构,实际部署时还需要考虑更多细节调整以及性能调优策略。 对于更深入的研究方向可以参考文献《Lane Detection Using Hough Transform Real-Time Lane Detection Using Deep Learning》[^2] ,其中探讨了几种改进措施包括但不限于引入注意力机制增强局部区域敏感度;采用多尺度融合提升小目标捕捉能力等等。 最后值得注意的是尽管目前存在许多优秀的开源项目可供借鉴如 https://github.com/Hanqer/deep-hough-transform 提供了完整的源码仓库便于快速上手实践但是随着自动驾驶行业的快速发展新的技术和理论层出不穷因此持续跟踪最新进展保持知识更新尤为重要。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值