hough变换

//c.h

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;

//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct tagBITMAPFILEHEADER{
//WORD bfType;//文件类型,必须是0x424D,即字符“BM”
DWORD bfSize;//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//信息头大小
LONG biWidth;//图像宽度
LONG biHeight;//图像高度
WORD biPlanes;//位平面数,必须为1
WORD biBitCount;//每像素位数
DWORD biCompression; //压缩类型
DWORD biSizeImage; //压缩图像大小字节数
LONG biXPelsPerMeter; //水平分辨率
LONG biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //位图实际用到的色彩数
DWORD biClrImportant; //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义

typedef struct tagRGBQUAD{
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
}RGBQUAD;//调色板定义

//像素信息
typedef struct tagIMAGEDATA
{
BYTE blue;
//BYTE green;
//BYTE red;
}IMAGEDATA;

#include <stdio.h>
#include "c.h"
#include "stdlib.h"
#include "math.h"
#include <iostream>

#define PI 3.14159//圆周率宏定义
#define LENGTH_NAME_BMP 30//bmp图片文件名的最大长度

using namespace std;

//变量定义
BITMAPFILEHEADER strHead;
RGBQUAD strPla[256];//256色调色板
BITMAPINFOHEADER strInfo;

//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead){
cout<<"位图文件头:"<<endl;
cout<<"文件大小:"<<pBmpHead.bfSize<<endl;
cout<<"保留字_1:"<<pBmpHead.bfReserved1<<endl;
cout<<"保留字_2:"<<pBmpHead.bfReserved2<<endl;
cout<<"实际位图数据的偏移字节数:"<<pBmpHead.bfOffBits<<endl<<endl;
}

void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead){
cout<<"位图信息头:"<<endl;
cout<<"结构体的长度:"<<pBmpInforHead.biSize<<endl;
cout<<"位图宽:"<<pBmpInforHead.biWidth<<endl;
cout<<"位图高:"<<pBmpInforHead.biHeight<<endl;
cout<<"biPlanes平面数:"<<pBmpInforHead.biPlanes<<endl;
cout<<"biBitCount采用颜色位数:"<<pBmpInforHead.biBitCount<<endl;
cout<<"压缩方式:"<<pBmpInforHead.biCompression<<endl;
cout<<"biSizeImage实际位图数据占用的字节数:"<<pBmpInforHead.biSizeImage<<endl;
cout<<"X方向分辨率:"<<pBmpInforHead.biXPelsPerMeter<<endl;
cout<<"Y方向分辨率:"<<pBmpInforHead.biYPelsPerMeter<<endl;
cout<<"使用的颜色数:"<<pBmpInforHead.biClrUsed<<endl;
cout<<"重要颜色数:"<<pBmpInforHead.biClrImportant<<endl;
}

//main.cpp
int main(){
char strFile[LENGTH_NAME_BMP];//bmp文件名
IMAGEDATA *imagedata = NULL;//动态分配存储原图片的像素信息的二维数组
IMAGEDATA *imagedataverage = NULL;//动态分配存储旋转后的图片的像素信息的二维数组
IMAGEDATA *imagedatalevel = NULL;
IMAGEDATA *imagedatavertical = NULL;
int width,height;//图片的宽度和高度
cout<<"请输入所要读取的文件名:"<<endl;
cin>>strFile;
FILE *fpi,*fpw;
fpi=fopen(strFile,"rb");
if(fpi != NULL){
//先读取文件类型
WORD bfType;
fread(&bfType,1,sizeof(WORD),fpi);
if(0x4d42!=bfType)
{
cout<<"the file is not a bmp file!"<<endl;
return (1);
}
//读取bmp文件的文件头和信息头
fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
//showBmpHead(strHead);//显示文件头
fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
//showBmpInforHead(strInfo);//显示文件信息头

//读取调色板
for(unsigned int nCounti=0;nCounti<strInfo.biClrUsed;nCounti++)
{
fread((char *)&(strPla[nCounti].rgbBlue),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbGreen),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbRed),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbReserved),1,sizeof(BYTE),fpi);
}

width = strInfo.biWidth;
height = strInfo.biHeight;
//图像每一行的字节数必须是4的整数倍
width = (width * sizeof(IMAGEDATA) + 3) / 4 * 4;
//imagedata = (IMAGEDATA*)malloc(width * height * sizeof(IMAGEDATA));
imagedata = (IMAGEDATA*)malloc(width * height);
imagedataverage = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
imagedatalevel = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
imagedatavertical = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
//初始化原始图片的像素数组
for(int i = 0;i < height;++i)
{
for(int j = 0;j < width;++j)
{
(*(imagedata + i * width + j)).blue = 0;
//(*(imagedata + i * width + j)).green = 0;
//(*(imagedata + i * width + j)).red = 0;
}
}
//初始化均衡化后图片的像素数组
for(int i = 0;i <height;++i)
{
for(int j = 0;j <width;++j)
{
(*(imagedataverage + i*width + j)).blue = 0;
//(*(imagedataverage + i*width + j)).green = 0;
//(*(imagedataverage + i*width + j)).red = 0;
}
}
//fseek(fpi,54,SEEK_SET);
//读出图片的像素数据
fread(imagedata,sizeof(struct tagIMAGEDATA) * width,height,fpi);
fclose(fpi);
}
else
{
cout<<"file open error!"<<endl;
return (1);
}
/*
//图片旋转处理
int RotateAngle;//要旋转的角度数
double angle;//要旋转的弧度数
int midX_pre,midY_pre,midX_aft,midY_aft;//旋转所围绕的中心点的坐标
midX_pre = width / 2;
midY_pre = height / 2;
midX_aft = width;
midY_aft = height;
int pre_i,pre_j,after_i,after_j;//旋转前后对应的像素点坐标
cout<<"输入要旋转的角度(0度到360度,逆时针旋转):"<<endl;
cin>>RotateAngle;
angle = 1.0 * RotateAngle * PI / 180;
for(int i = 0;i < 2 * height;++i)
{
for(int j = 0;j < 2 * width;++j)
{
after_i = i - midX_aft;//坐标变换
after_j = j - midY_aft;
pre_i = (int)(cos((double)angle) * after_i - sin((double)angle) * after_j) + midX_pre;
pre_j = (int)(sin((double)angle) * after_i + cos((double)angle) * after_j) + midY_pre;
if(pre_i >= 0 && pre_i < height && pre_j >= 0 && pre_j < width)//在原图范围内
*(imagedataRot + i * 2 * width + j) = *(imagedata + pre_i * width + pre_j);
}
} */

//sober
for (int i=0;i<height;i++)
for (int j=0;j<width;j++)
{
(*(imagedatalevel + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
(*(imagedatavertical + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
(*(imagedataverage + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
}

for ( int i=1;i<height-1;i++)
for (int j=1;j<width-1;j++)
{
(*(imagedatalevel + i * width + j)).blue =
abs((*(imagedata + (i + 1) * width + j - 1)).blue - (*(imagedata + (i - 1) * width + j - 1)).blue +
2 * ((*(imagedata + (i + 1) * width + j)).blue - (*(imagedata + (i - 1) * width + j)).blue) +
(*(imagedata + (i + 1) * width + j + 1)).blue - (*(imagedata + (i - 1) * width + j + 1)).blue);
(*(imagedatavertical + i * width + j)).blue =
abs((*(imagedata + (i - 1) * width + j + 1)).blue - (*(imagedata + (i - 1) * width + j - 1)).blue +
2 * ((*(imagedata + i * width + j + 1)).blue - (*(imagedata + i * width + j - 1)).blue) +
(*(imagedata + (i + 1) * width + j + 1)).blue - (*(imagedata + (i + 1) * width + j - 1)).blue);
}
int s;
for (int i=1;i<height-1;i++)
for (int j=1;j<width-1;j++)
{
s=(int)(*(imagedatalevel + i*width + j)).blue+ (int)(*(imagedatavertical+ i*width + j)).blue;
if(s>255)
(*(imagedataverage + i*width + j)).blue=(BYTE)255;
else
(*(imagedataverage + i*width + j)).blue=(BYTE)s;

}

int k=(int)sqrt(width*width+height*height);//k为原图对角线距离
int p=0;
double A[270][k];
for(int i=0;i<270;i++)
for(int j=0;j<k;j++)
{A[i][j]=0;
}
for (int i=1;i<height;i++)
for (int j=1;j<width;j++)
{
float rho = (int)(atan(1.0*i/j)*180/PI);
if((imagedataverage+i*width+j)->blue < 126)continue;//限制灰度范围
for (int m=90-rho;m<270-rho;m++)
{
if((m%90==0)||(abs(m-225)<15)||(abs(m-135)<10))//限制角度范围来限制直线的范围
{
float t=((m-90)/180.0)*PI;
p=(int)(i*cos(t)+j*sin(t));//计算极径p
if(p<k)
A[m][p]++;
}
}
}
for (int i=1;i<height;i++)
for (int j=1;j<width;j++)
{
float rho = (int)(atan(1.0*i/j)*180/PI);
for (int m=90-rho;m<270-rho;m++)
{
float t=((m-90)/180.0)*PI;
p=(int)(i*cos(t)+j*sin(t));
if(p<k&&A[m][p] > 175)
(*(imagedata + i*width + j)).blue=255;

}
}

//保存bmp图片
if((fpw=fopen("result.bmp","wb"))==NULL)
{
cout<<"create the bmp file error!"<<endl;
return (1);
}
WORD bfType_w=0x4d42;
fwrite(&bfType_w,1,sizeof(WORD),fpw);
//fpw +=2;
fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
strInfo.biWidth = width;
strInfo.biHeight = height;
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存调色板数据
for(unsigned int nCounti=0;nCounti<strInfo.biClrUsed;nCounti++)
{
fwrite(&strPla[nCounti].rgbBlue,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbGreen,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbRed,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbReserved,1,sizeof(BYTE),fpw);
}
//保存像素数据
for( int i =0;i < height;++i)
{
for(int j = 0;j < width;++j)
{
fwrite( &((*(imagedata + i * width + j)).blue),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataverage + i * 2 * width + j)).green),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataverage + i * 2 * width + j)).red),1,sizeof(BYTE),fpw);
}
}
fclose(fpw);

//释放内存
delete[] imagedata;
delete[] imagedataverage;
}

#include <stdio.h>
#include "c.h"
#include "stdlib.h"
#include "math.h"
#include <iostream>

#define PI 3.14159//圆周率宏定义
#define LENGTH_NAME_BMP 30//bmp图片文件名的最大长度

using namespace std;

//变量定义
BITMAPFILEHEADER strHead;
RGBQUAD strPla[256];//256色调色板
BITMAPINFOHEADER strInfo;

//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead){
cout<<"位图文件头:"<<endl;
cout<<"文件大小:"<<pBmpHead.bfSize<<endl;
cout<<"保留字_1:"<<pBmpHead.bfReserved1<<endl;
cout<<"保留字_2:"<<pBmpHead.bfReserved2<<endl;
cout<<"实际位图数据的偏移字节数:"<<pBmpHead.bfOffBits<<endl<<endl;
}

void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead){
cout<<"位图信息头:"<<endl;
cout<<"结构体的长度:"<<pBmpInforHead.biSize<<endl;
cout<<"位图宽:"<<pBmpInforHead.biWidth<<endl;
cout<<"位图高:"<<pBmpInforHead.biHeight<<endl;
cout<<"biPlanes平面数:"<<pBmpInforHead.biPlanes<<endl;
cout<<"biBitCount采用颜色位数:"<<pBmpInforHead.biBitCount<<endl;
cout<<"压缩方式:"<<pBmpInforHead.biCompression<<endl;
cout<<"biSizeImage实际位图数据占用的字节数:"<<pBmpInforHead.biSizeImage<<endl;
cout<<"X方向分辨率:"<<pBmpInforHead.biXPelsPerMeter<<endl;
cout<<"Y方向分辨率:"<<pBmpInforHead.biYPelsPerMeter<<endl;
cout<<"使用的颜色数:"<<pBmpInforHead.biClrUsed<<endl;
cout<<"重要颜色数:"<<pBmpInforHead.biClrImportant<<endl;
}

int main(){
char strFile[LENGTH_NAME_BMP];//bmp文件名
IMAGEDATA *imagedata = NULL;//动态分配存储原图片的像素信息的二维数组
IMAGEDATA *imagedataverage = NULL;//动态分配存储旋转后的图片的像素信息的二维数组
IMAGEDATA *imagedatalevel = NULL;
IMAGEDATA *imagedatavertical = NULL;
int width,height;//图片的宽度和高度
cout<<"请输入所要读取的文件名:"<<endl;
cin>>strFile;
FILE *fpi,*fpw;
fpi=fopen(strFile,"rb");
if(fpi != NULL){
//先读取文件类型
WORD bfType;
fread(&bfType,1,sizeof(WORD),fpi);
if(0x4d42!=bfType)
{
cout<<"the file is not a bmp file!"<<endl;
return (1);
}
//读取bmp文件的文件头和信息头
fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
//showBmpHead(strHead);//显示文件头
fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
//showBmpInforHead(strInfo);//显示文件信息头

//读取调色板
for(unsigned int nCounti=0;nCounti<strInfo.biClrUsed;nCounti++)
{
fread((char *)&(strPla[nCounti].rgbBlue),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbGreen),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbRed),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbReserved),1,sizeof(BYTE),fpi);
}

width = strInfo.biWidth;
height = strInfo.biHeight;
//图像每一行的字节数必须是4的整数倍
width = (width * sizeof(IMAGEDATA) + 3) / 4 * 4;
//imagedata = (IMAGEDATA*)malloc(width * height * sizeof(IMAGEDATA));
imagedata = (IMAGEDATA*)malloc(width * height);
imagedataverage = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
imagedatalevel = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
imagedatavertical = (IMAGEDATA*)malloc(width *height * sizeof(IMAGEDATA));
//初始化原始图片的像素数组
for(int i = 0;i < height;++i)
{
for(int j = 0;j < width;++j)
{
(*(imagedata + i * width + j)).blue = 0;
//(*(imagedata + i * width + j)).green = 0;
//(*(imagedata + i * width + j)).red = 0;
}
}
//初始化均衡化后图片的像素数组
for(int i = 0;i <height;++i)
{
for(int j = 0;j <width;++j)
{
(*(imagedataverage + i*width + j)).blue = 0;
//(*(imagedataverage + i*width + j)).green = 0;
//(*(imagedataverage + i*width + j)).red = 0;
}
}
//fseek(fpi,54,SEEK_SET);
//读出图片的像素数据
fread(imagedata,sizeof(struct tagIMAGEDATA) * width,height,fpi);
fclose(fpi);
}
else
{
cout<<"file open error!"<<endl;
return (1);
}
/*
//图片旋转处理
int RotateAngle;//要旋转的角度数
double angle;//要旋转的弧度数
int midX_pre,midY_pre,midX_aft,midY_aft;//旋转所围绕的中心点的坐标
midX_pre = width / 2;
midY_pre = height / 2;
midX_aft = width;
midY_aft = height;
int pre_i,pre_j,after_i,after_j;//旋转前后对应的像素点坐标
cout<<"输入要旋转的角度(0度到360度,逆时针旋转):"<<endl;
cin>>RotateAngle;
angle = 1.0 * RotateAngle * PI / 180;
for(int i = 0;i < 2 * height;++i)
{
for(int j = 0;j < 2 * width;++j)
{
after_i = i - midX_aft;//坐标变换
after_j = j - midY_aft;
pre_i = (int)(cos((double)angle) * after_i - sin((double)angle) * after_j) + midX_pre;
pre_j = (int)(sin((double)angle) * after_i + cos((double)angle) * after_j) + midY_pre;
if(pre_i >= 0 && pre_i < height && pre_j >= 0 && pre_j < width)//在原图范围内
*(imagedataRot + i * 2 * width + j) = *(imagedata + pre_i * width + pre_j);
}
} */

//sober
for (int i=0;i<height;i++)
for (int j=0;j<width;j++)
{
(*(imagedatalevel + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
(*(imagedatavertical + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
(*(imagedataverage + i*width + j)).blue=(*(imagedata + i*width + j)).blue;
}

for ( int i=1;i<height-1;i++)
for (int j=1;j<width-1;j++)
{
(*(imagedatalevel + i * width + j)).blue =
abs((*(imagedata + (i + 1) * width + j - 1)).blue - (*(imagedata + (i - 1) * width + j - 1)).blue +
2 * ((*(imagedata + (i + 1) * width + j)).blue - (*(imagedata + (i - 1) * width + j)).blue) +
(*(imagedata + (i + 1) * width + j + 1)).blue - (*(imagedata + (i - 1) * width + j + 1)).blue);
(*(imagedatavertical + i * width + j)).blue =
abs((*(imagedata + (i - 1) * width + j + 1)).blue - (*(imagedata + (i - 1) * width + j - 1)).blue +
2 * ((*(imagedata + i * width + j + 1)).blue - (*(imagedata + i * width + j - 1)).blue) +
(*(imagedata + (i + 1) * width + j + 1)).blue - (*(imagedata + (i + 1) * width + j - 1)).blue);
}
int s;
for (int i=1;i<height-1;i++)
for (int j=1;j<width-1;j++)
{
s=(int)(*(imagedatalevel + i*width + j)).blue+ (int)(*(imagedatavertical+ i*width + j)).blue;
if(s>255)
(*(imagedataverage + i*width + j)).blue=(BYTE)255;
else
(*(imagedataverage + i*width + j)).blue=(BYTE)s;

}

int k=(int)sqrt(width*width+height*height);//k为原图对角线距离
int p=0;
double A[270][k];
for(int i=0;i<270;i++)
for(int j=0;j<k;j++)
{A[i][j]=0;
}
for (int i=1;i<height;i++)
for (int j=1;j<width;j++)
{
float rho = (int)(atan(1.0*i/j)*180/PI);
if((imagedataverage+i*width+j)->blue < 126)continue;//限制灰度范围
for (int m=90-rho;m<270-rho;m++)
{
if((m%90==0)||(abs(m-225)<15)||(abs(m-135)<10))//限制角度范围来限制直线的范围
{
float t=((m-90)/180.0)*PI;
p=(int)(i*cos(t)+j*sin(t));//计算极径p
if(p<k)
A[m][p]++;
}
}
}
for (int i=1;i<height;i++)
for (int j=1;j<width;j++)
{
float rho = (int)(atan(1.0*i/j)*180/PI);
for (int m=90-rho;m<270-rho;m++)
{
float t=((m-90)/180.0)*PI;
p=(int)(i*cos(t)+j*sin(t));
if(p<k&&A[m][p] > 175)
(*(imagedata + i*width + j)).blue=255;

}
}

//保存bmp图片
if((fpw=fopen("result.bmp","wb"))==NULL)
{
cout<<"create the bmp file error!"<<endl;
return (1);
}
WORD bfType_w=0x4d42;
fwrite(&bfType_w,1,sizeof(WORD),fpw);
//fpw +=2;
fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
strInfo.biWidth = width;
strInfo.biHeight = height;
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存调色板数据
for(unsigned int nCounti=0;nCounti<strInfo.biClrUsed;nCounti++)
{
fwrite(&strPla[nCounti].rgbBlue,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbGreen,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbRed,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbReserved,1,sizeof(BYTE),fpw);
}
//保存像素数据
for( int i =0;i < height;++i)
{
for(int j = 0;j < width;++j)
{
fwrite( &((*(imagedata + i * width + j)).blue),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataverage + i * 2 * width + j)).green),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataverage + i * 2 * width + j)).red),1,sizeof(BYTE),fpw);
}
}
fclose(fpw);

//释放内存
delete[] imagedata;
delete[] imagedataverage;
}

时间: 2024-08-21 08:16:23

hough变换的相关文章

hough变换检测直线

hough变换检测直线原理: 假设在图像中存在一条直线y=k*x+b(此时k,b未知).取直线上的任意两点进行说明,设为(x0,y0),(x1,y1). 所有经过点(x0,y0)的直线满足:-x0*k+y0=b ---式1,那么以k.b为直角坐标轴做式1对应直线: 所有经过点(x1,y1)的直线满足:-x1*k+y1=b ---式2,那么以k.b为直角坐标轴做式2对应直线: 两直线交于一点(kk,bb),此时该交点对应的直线y=kk*x+bb就是(x0,y0),(x1,y1)所确定的直线. 在h

Python下opencv使用笔记(十一)(详解hough变换检测直线与圆)

在数字图像中,往往存在着一些特殊形状的几何图形,像检测马路边一条直线,检测人眼的圆形等等,有时我们需要把这些特定图形检测出来,hough变换就是这样一种检测的工具. Hough变换的原理是将特定图形上的点变换到一组参数空间上,根据参数空间点的累计结果找到一个极大值对应的解,那么这个解就对应着要寻找的几何形状的参数(比如说直线,那么就会得到直线的斜率k与常熟b,圆就会得到圆心与半径等等). 关于hough变换,核心以及难点就是关于就是有原始空间到参数空间的变换上.以直线检测为例,假设有一条直线L,

Hough变换直线检测

Hough变换直线检测 [email protected] http://blog.csdn.net/kezunhai 霍夫变换是图像变换中的经典算法之一,主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等).霍夫变换寻找直线与圆的方法相比与其它方法可以更好的减少噪声干扰.Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的曲线通过转换到参数空间的一个点. 从图中可以看到,x-y坐标和K-b坐标有点--线的对偶性.x-y坐标中的P1.P2对应于k-b坐标中的L1.L2:

基于VB的hough变换和任意角度旋转

Public Sub DoRotate(Optional ByVal RotaryAngle As Long = 0) '任意角度旋转 Dim sDIB As New cDIB Dim sBits() As RGBQUAD Dim dBits() As RGBQUAD Dim stSA As SAFEARRAY2D Dim dtSA As SAFEARRAY2D Dim Lev As Long Dim Wgt As Long Dim x As Long Dim y As Long Dim new

Hough变换检测椭圆

 由椭圆的公式(1)可得,确定一个椭圆需要5个参数,a,b 为椭圆的长轴和段轴,P,Q 为椭圆中心坐标,θ为椭圆的旋转角度.如果用传统的Hough变换方法,参数空间需要五维.这种方法在计算过程中所耗费的时间和空间资源是惊人的,根本无法应用于实际.为此,人们提出了很多新的改进算法. 改进算法主要分为两种: 1)随机Hough变换(RHT),采用多到一的映射,但是随机采样会带来大量无效的计算,当点数很大时,算法的性能急剧下降. 2)利用椭圆的几何特征降低参数的维度. 本文所提出的椭圆检测方法也是基于

毕业课题之------------图像的直线提取--hough变换

图像处理程序中经常要用到直线检测,常用的直线检测方法是Hough变换.Hough变换是图像处理中从图像中识别几何形状的基本方法之一.Hough变换的基本原理在于 利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点.这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问 题.也即把检测整体特性转化为检测局部特性.比如直线.椭圆.圆.弧线等. 简而言之,Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应

Hough变换-理解篇

Hough变换-理解篇 霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体.该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果.霍夫变换于1962年由Paul Hough 首次提出[53],后于1972年由Richard Duda和Peter Hart推广使用[54],经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆. 霍夫变换运用两个坐标空间之间的变换

Matlab实现Hough变换检测图像中的直线

Hough变换的原理: 将图像从图像空间变换至参数空间,变换公式如下: 变换以后,图像空间与参数空间存在以下关系: 图像空间中的一点在参数空间是一条曲线,而图像空间共线的各点对应于参数空间交于一点的各条曲线. 下面使用Matlab实现Hough变换对图像中的直线划痕进行检测. close all; clear all; I = imread('scratch.tif'); figure; subplot(1,3,1); imshow(I); BW = edge(I,'canny');%Canny

Hough 变换

作用 霍夫变换是常用的图像变换,用于在图像中寻找直线.圆.椭圆等这类具有相同特征的几何图形.在许多应用场合中,都需要实现对特定形状物体的快速定位,而霍夫变换由于其对方向和噪声不敏感,因此在这类应用中发挥着重要作用. 原理 霍夫变换最基本的思想通俗讲就是将图像中所有可能出现的几何图形位置进行遍历,以直线检测为例,就是在整幅图像中进行扫描所有可能的直线,看图像中的像素点对各直线的贡献.下面以直线为例,形象地进行介绍: 图 1.霍夫变换示意图 如图1所示,矩形点阵表示图像,黑色的点表示边缘的像素点.霍

Hough变换检测圆(附:MATLAB程序) - mhjerry的专栏(子水) - 博客频道 - CSDN.NET

来源:http://blog.csdn.net/mhjerry/article/details/7061819#1536434-hi-1-45330-42d97150898b1af15ddaae52f91f09c2 Hough变换很好玩,以前在学校写过一些检测圆圈.椭圆.双曲线等图像,同时也可以检测多个圆形.