当前位置:网站首页>hough变换检测直线原理(opencv霍夫直线检测)
hough变换检测直线原理(opencv霍夫直线检测)
2022-07-31 15:05:00 【全栈程序员站长】
大家好,又见面了,我是你们的朋友全栈君。
直线的霍夫变换:
霍夫空间极坐标与图像空间的转换公式: 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.cn/128252.html原文链接:https://javaforall.cn
边栏推荐
猜你喜欢
TCP详解
女性服务社群产品设计
Public Key Retrieval is not allowed error solution when DBeaver connects to MySQL 8.x
"Listen to me, thank you" can be said in ancient poetry?Tsinghua University has developed an artifact of "Searching Sentences According to Meaning", which can search for the famous sayings you want wi
为什么毕业季不要表白?
LeetCode二叉树系列——222.完全二叉树的节点个数
「秋招系列」MySQL面试核心25问(附答案)
【CUDA学习笔记】初识CUDA
Sentinel安装与部署
工程力学复习资料
随机推荐
《微信小程序-进阶篇》Lin-ui组件库源码分析-Icon组件
易驱线主控芯片对比(电动三轮电机90O瓦世纪通达)
Efficient use of RecyclerView Section 3
2021 OWASP TOP 10 漏洞指南
Getting started with UnityShader (1) - GPU and Shader
最小费用最大流问题详解
Emmet 语法
Public Key Retrieval is not allowed error solution when DBeaver connects to MySQL 8.x
UnityShader入门学习(一)——GPU与Shader
LeetCode二叉树系列——222.完全二叉树的节点个数
OpenCV测量物体的尺寸技能 get~
网线RJ45接口针脚[通俗易懂]
Ubantu专题4:xshell、xftp连接接虚拟机以及设置xshell复制粘贴快捷键
Gorm—Go语言数据库框架
NPM Taobao mirror (latest version) released a new version of npm mirror at 2021-11-21 16:53:52 [easy to understand]
Female service community product design
svn安装及使用(身体功能手册)
公告
Redis与分布式:主从复制
C language basic practice (nine-nine multiplication table) and printing different asterisk patterns