hough变换检测直线原理(opencv霍夫直线检测)

直线的霍夫变换:霍夫空间极坐标与图像空间的转换公式:p=y*sin(theta)+x*cos(theta);之后遍历图像的每个坐标点,每个坐标点以一度为增量,求取对应的p值,存入数组中,查找数组中数目大于一定阈值的p和theta,再在图像空间中把直线恢复出来霍夫变换就是把图像左边空间上的线段转换到霍夫空间一个点,然后通过点的数目多少来确定是否为一条线段(但是画出的结果为一条

大家好,又见面了,我是你们的朋友全栈君。

直线的霍夫变换:

霍夫空间极坐标与图像空间的转换公式:
p = y * sin(theta) + x * cos(theta);

之后遍历图像的每个坐标点,每个坐标点以一度为增量,求取对应的p值,存入数组中,查找数组中数目大于一定阈值的p和theta,再在图像空间中把 直线 恢复出来

霍夫变换就是把图像左边空间上的线段转换到霍夫空间一个点,然后通过点的数目多少来确定是否为一条线段(但是画出的结果为一条直线)

实现代码如下:

#include <iostream>
#include "gdal_priv.h"
#include <string>
using namespace std;


//图像的膨胀
//算法的实现依然有重复的地方,会造成空间和时间上的浪费,但是效果还可以,暂定如此,如有好的算法再进行改进
void Expand(unsigned char* date,unsigned char* ExpandImage,int Width,int Height)
{
    int x, y;
    int Direction[8][2] = {-1, -1, 0, -1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, -1, 0};
    int Index;


    for(int i = 1;i < Height - 1;++i)
    {
        for(int j = 1;j < Width - 1;++j)
        {
            if(date[i * Width + j] == 255)
            {
                for(int k = 0;k < 8;++k)
                {
                    x = i + Direction[k][0];
                    y = j + Direction[k][1];
                    Index = x * Width + y;

                    ExpandImage[Index] = 255;

                }
            }
        }
    }


    return;
}

//图像的腐蚀
void Erosion(unsigned char* date,unsigned char* ErosionImage,int Width,int Height)
{
    int x, y;
    int Direction[8][2] = {-1, -1, 0, -1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, -1, 0};
    int Index;


    for(int i = 1;i < Height - 1;++i)
    {
        for(int j = 1;j < Width - 1;++j)
        {
            if(date[i * Width + j] == 0)
            {
                for(int k = 0;k < 8;++k)
                {
                    x = i + Direction[k][0];
                    y = j + Direction[k][1];
                    Index = x * Width + y;

                    ErosionImage[Index] = 0;

                }
            }
        }
    }



    return;
}

//图像相减求边界
void Subtraction(unsigned char* ResultImage,unsigned char* leftImage,unsigned char* rightImage,int Width,int Height)
{
    int Index;
    for(int i = 0;i < Height;++i)
        for(int j = 0;j < Width;++j)
        {
            Index = i * Width + j;
            ResultImage[Index] = leftImage[Index] - rightImage[Index];
        }

    return ;
}

void FindBoundary(unsigned char* image,unsigned char* tempImage,int Width,int Height)
{
    //生成对于图像膨胀的图像
    unsigned char* ExpandImage = new unsigned char[Width * Height];
    memset(ExpandImage,0,sizeof(unsigned char) * Width * Height);

    Expand(image ,ExpandImage,Width ,Height);


    Subtraction(tempImage,ExpandImage,image,Width,Height);
}


/************************************************************************* * 直线的Hough检测 * 参数:image0为原图形,image1为边缘检测结果,w、h为图像的宽和高 * 由于得到的Hough变换结果图像与原图像大小不同,为了得到新的宽高信息 * w、h使用引用类型 *************************************************************************/
unsigned char** HoughLine(unsigned char* image0, unsigned char* &tempImage, int &Width, int &Height,int scale=1)
{
    //定义三角函数表
    double sinValue[360];
    double cosValue[360];
    int i,x,y;
    int k = 100;
    int p = (int)(sqrt((double)(Width * Width + Height * Height) + 1));   //计算对角线长度
    //申请临时存储空间 用来保存边缘检测结果
// tempImage = new unsigned char[Width * Height];
    memset(tempImage,0,sizeof(unsigned char) * Width * Height);
    //边缘检测
// SideGrandiant(image0, tempImage, Width, Height);
    FindBoundary(image0, tempImage, Width, Height);





// //根据Hough变换结果图的大小 重新为输出图象分配空间
// if(image1 != NULL) 
// delete image1;
//
 image1 = (BYTE*)malloc(sizeof(BYTE)*p*360*4);
//
// image1 = new unsigned char[p * 360];
// memset(image1,0,p * 360);

    //将图像转换为矩阵形式
// BYTE** HoughBuf =CreatImage(image1,360,p);

    unsigned char** HoughBuf = new unsigned char* [p];
    for(int i = 0;i < p;++i)
    {
        HoughBuf[i] = new unsigned char[360];
        memset(HoughBuf[i],0,sizeof(unsigned char) * 360);
        //HoughBuf[i] = image1 + i * 360;
    }

    //for(int i = 0;i < p;++i)
    //{ 
   
    // for(int j = 0;j < 360;++j)
    // HoughBuf[i][j] = image1[i * 360 + j];
    //}
    //计算三角函数表
    for(i=0; i<360 ; i++)
    {
        sinValue[i] = sin(i*3.1415926/180);
        cosValue[i] = cos(i*3.1415926/180);
    }
    int tp;
    //遍历原图象中的每个像素
    for(y = 0; y < Height; y++)
        for(x = 0; x < Width; x++)
        {
            //对经过当前像素的任何直线区域进行检测
            for(i = 0; i < 360; i++)
            {
                if( tempImage[(y * Width + x)] > k )
                {
                    tp = (int)( x * sinValue[i] + y * cosValue[i]);
                    //忽略负数同时防止计数器溢出
                    if (tp < 0 || HoughBuf[tp][i] == 255) continue;
                    HoughBuf[tp][i] += scale;
                }
            }
        }
    //重新设定图象大小
    //Width = 360;
    //Height = p;

// delete tempImage;

    return HoughBuf;
}


//画检测到的直线
void DrawLine(unsigned char* LineIamge,int Width,int Height,int p,int theta)
{
    double k,b;
    int x,y;
    if(theta != 90)    //如果斜率存在
    {
        //计算直线方程的参数
        b = p / cos(theta * 3.1415926535 / 180);
        k = -sin(theta * 3.1415926535 / 180) / cos(theta * 3.1415926535 / 180);
        y=0;
        x=0;
        //斜率小于1的情况
        if(abs(k) <= 1)
        {
            for(x = 0;x < Width;x++)
            {
                y=(int)(k * x + b);
                if(y >= 0 && y < Height)
                {
                    LineIamge[y * Width + x] = 255;
                }
            }
        }
        //斜率大于1的情况
        else
        {
            for(y = 0;y < Height;y++)
            {
                x = (int)(y / k - b / k);
                if(x >= 0 && x < Width)
                {
                    /*imageBuf[y][x*4]=255; imageBuf[y][x*4+1]=0; imageBuf[y][x*4+2]=0; imageBuf[y][x*4+3]=255;*/
                    LineIamge[y * Width + x] = 255;
                }
            }
        }
    }
    //斜率不存在的情况
    else
    {
        for(y = 0; y < Height;y++)
        {
            /*imageBuf[y][p*4]=255; imageBuf[y][p*4+1]=0; imageBuf[y][p*4+2]=0; imageBuf[y][p*4+3]=255;*/
            LineIamge[y * Width + p] = 255;
        }
    }
}



int main()
{
    GDALAllRegister();
    CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");

    string str1="1.1.bmp";
    string str2="1.2.tif";
    string str3 = "1.3.tif";

    GDALDataset* pInDataset=(GDALDataset*)GDALOpen(str1.data() ,GA_ReadOnly);

    if(pInDataset == nullptr)
    {
        cout<<"未找到输入图像"<<endl;
        getchar();
        return 1;
    }

    int Width=pInDataset->GetRasterXSize();
    int Height = pInDataset->GetRasterYSize();
    int band = pInDataset->GetRasterCount();

    double dGeoTrans[6]={};
    pInDataset->GetGeoTransform(dGeoTrans);
    const char* cProjectionRef = pInDataset->GetProjectionRef();

    unsigned char* Image = new unsigned char[Width * Height];
    GDALRasterBand* pRasterBand = pInDataset->GetRasterBand(1);

    CPLErr err=pRasterBand->RasterIO(GF_Read ,0 ,0 ,Width ,Height ,Image ,Width ,Height ,GDT_Byte ,0,0);

    unsigned char* ResultImage = new unsigned char[Width * Height];//保存图像的边缘信息,通过膨胀后的图像减去原始图像得到的边缘图像,用来检测是否得到了边缘
    //ResultImage = nullptr;
    //unsigned char** HoughBuf = nullptr;
    unsigned char** HoughBuf;
    HoughBuf = HoughLine(Image,ResultImage,Width,Height);



    GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");

    GDALDataset* pOutDataset = pDriver->Create("1.2.tif" ,Width ,Height ,1 ,GDT_Byte ,NULL);
    GDALRasterBand* pOutRasterband=pOutDataset->GetRasterBand(1);
    pOutRasterband->RasterIO(GF_Write ,0 ,0 ,Width ,Height ,ResultImage ,Width ,Height ,GDT_Byte ,0 ,0);


    int p = (int)(sqrt((double)(Width * Width + Height * Height) + 1));   //计算对角线长度

    unsigned char* LineImage = new unsigned char[Width * Height];
    memset(LineImage,0,sizeof(unsigned char) * Width * Height);

    if(HoughBuf != nullptr)
        for(int i = 0;i < p;++i)
        {
            for(int j = 0;j < 360;++j)
            {
                if(HoughBuf[i][j] > 200)        //设置阈值为200,可自行设置
                {
                    cout<<(int)HoughBuf[i][j]<<" ";
                    DrawLine(LineImage,Width,Height,i,j);//得到的结果为一条直线
                }
            }
            cout<<"***************"<<endl;
        }

    GDALDriver* pLineDriver = GetGDALDriverManager()->GetDriverByName("GTiff");

    GDALDataset* pOutLineDataset = pLineDriver->Create("1.3.tif" ,Width ,Height ,1 ,GDT_Byte ,NULL);
    GDALRasterBand* pOutLineRasterband=pOutLineDataset->GetRasterBand(1);
    pOutLineRasterband->RasterIO(GF_Write ,0 ,0 ,Width ,Height ,LineImage ,Width ,Height ,GDT_Byte ,0 ,0);

    delete Image;
    delete ResultImage;
    delete LineImage;
    for(int i = 0;i < p;++i)
        delete HoughBuf[i];
    delete HoughBuf;

    GDALClose(pOutDataset);
    GDALClose(pInDataset);
    GDALClose(pOutLineDataset);
    GetGDALDriverManager()->DeregisterDriver(pDriver);
    GetGDALDriverManager()->DeregisterDriver(pLineDriver);

    system("pause");
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/128252.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 3500元计算机基本硬件配置清单,电脑硬件中配配置清单

    3500元计算机基本硬件配置清单,电脑硬件中配配置清单电脑硬件中配配置清单导语:攒机一直是电脑爱好者热衷的事,自己选购各配件,组装一台适合自己要求的机器给很多DIYer带来了极大的欢乐。下面小编为你整理的电脑硬件中配配置清单,希望对你有所帮助!电脑硬件中配配置清单1、实用性机型建议:首选1:intelG1620双核+H61M主板。(价格低廉性能不弱,超值!)首选2:intelG1840双核+H81M主板。(核心显卡性能比G1620更强)2、中级机…

    2022年7月12日
    14
  • 网络学习 局域网分类 以太网 令牌网 FDDI光纤分布式数据接口网 异步传输模式网(ATM) 无线局域网

    网络学习 局域网分类 以太网 令牌网 FDDI光纤分布式数据接口网 异步传输模式网(ATM) 无线局域网局域网虽然目前我们所能看到的局域网主要是以双绞线为代表传输介质的以太网,那只不过是我们所看到都基本上是企、事业单位的局域网,在网络发展的早期或在其它各行各业中,因其行业特点所采用的局域网也不一定都是以太网,目前在局域网中常见的有:以太网(Ethernet)、令牌网(TokenRing)、FDDI网、异步传输模式网(ATM)等几类,下面分别作一些简要介绍。1以太网是这样通信的,每台电…

    2022年9月21日
    3
  • 详解List的toArray()方法和toArray(T[] a)方法

    详解List的toArray()方法和toArray(T[] a)方法这两个方法都是将列表List中的元素转导出为数组,不同的是,toArray()方法导出的是Object类型数组,而toArray[T[]a]方法导出的是指定类型的数组。下面是两个方法的申明及说明,摘自Java8的API文档。toArray()方法的分析Object[]toArray()Returnsanarraycontainingalloftheelementsinthislistinpropersequence(fromfirsttolastelem

    2022年5月14日
    45
  • vue:详解vue中的代理proxy

    vue:详解vue中的代理proxy问题我们本地调试一般都是 npmrunserve 然后打开本机 ip 8080 localhost 8080 对吧 这时候我们要调接口调试 后端的接口的地址可能在测试环境 也可能是自己电脑的 ip 总之不是你的 lcoalhost 8080 那么你调接口就会产生跨域 那么怎么办呢 就需要 proxy 出场了复习一下跨域的解决方案 jsonpcorsNod 中间件代理 两次跨域 nginx 反向代理 CORS 支持所有类型的 HTTP 请求 是跨域 HTTP 请求的根本解决方案 JSONP 只支持 GET 请求

    2025年7月29日
    3
  • stopwords.txt中英文数据集,四川大学机器智能实验室停用词库,哈工大停用词表,中文停用词表,百度停用词表百度网盘下载

    stopwords.txt中英文数据集,四川大学机器智能实验室停用词库,哈工大停用词表,中文停用词表,百度停用词表百度网盘下载今天找stopwords.txt数据集找了好长时间,真是气死了,好多都是需要金币,这数据集不是应该共享的么。故搜集了一些数据集,主要包括四川大学机器智能实验室停用词库,哈工大停用词表,中文停用词表,百度停用词表和一些其他的stopword.text。最后用python将这些数据集合并成一个完整的数据集stopword.txt。百度网盘地址在链接:https://pan.baidu.com/s/1KBkOzYk-wRYaWno6HSOE9g提取码:4sm6文件不是很大可以直接下载。下面是详细的目录。

    2022年6月24日
    26
  • hive sql分页[通俗易懂]

    hive sql分页[通俗易懂]查出线上线下会员支付超过100的 select*from(  selecta.id,b.mobile,a.totalmoneyfrom (SELECTsum(totalmoney)totalmoney,idFROM  (SELECTt.totalmoney,d.idFROM(  SELECTsum(totalmoney)totalmoney,vipcardn…

    2022年10月21日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号