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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • pytest parametrize fixture_参数化查询

    pytest parametrize fixture_参数化查询前言当某个接口中的一个字段,里面规定的范围为1-5,你5个数字都要单独写一条测试用例,就太麻烦了,这个时候可以使用pytest.mark.parametrize装饰器可以实现测试用例参数化。官方示

  • 矩阵转置基本性质

    矩阵转置基本性质一个矩阵的转置与本身相乘得到对称矩阵

  • java swt griddata_SWT中GridLayout 和GridData的使用

    java swt griddata_SWT中GridLayout 和GridData的使用1.[代码][Java]代码packagecn.haibin.rcp.test.layer;importorg.eclipse.jface.viewers.TableViewer;importorg.eclipse.swt.SWT;importorg.eclipse.swt.layout.GridData;importorg.eclipse.swt.layout.GridLayout;i…

  • RGB-D(深度图像) & 图像深度「建议收藏」

    RGB-D(深度图像) & 图像深度「建议收藏」RGB-D(深度图像)  深度图像=普通的RGB三通道彩色图像+DepthMap  在3D计算机图形中,DepthMap(深度图)是包含与视点的场景对象的表面的距离有关的信息的图像或图像通道。其中,DepthMap类似于灰度图像,只是它的每个像素值是传感器距离物体的实际距离。通常RGB图像和Depth图像是配准的,因而像素点之间具有一对一的对应关系

  • blender2.9教程_赖世雄入门篇

    blender2.9教程_赖世雄入门篇Blender2.8基础(一)基础操作与常用快捷键▶Ctrl+N:创建新工程一、视图操作1、放大视图▶视图最大化显示:Ctrl+空格(左键点击视图任意地方可以选择视图,然后按Ctrl+空格可以最大化显示视图。)▶切换全屏模式:Ctrl+Alt+空格2、切换视图▶切换视图:Alt(按住不放)+按住中键上下或左右移动鼠标(每切换一次视图就必须重新按一下中键并移动鼠标)▶……

  • C# ExecuteReader「建议收藏」

    C# ExecuteReader「建议收藏」classProgram{staticvoidMain(string[]args){//连接数据库using(MySqlConnectionconn=newMySqlConnection("Server=localhost;Database=study;uid=root;pw…

发表回复

您的电子邮箱地址不会被公开。

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