📄 featurealgrithm.cpp
字号:
// FeatureAlgrithm.cpp: implementation of the CFeatureAlgrithm class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MYFUSION.h"
#include "FeatureAlgrithm.h"
#include "dibapi.h"
#include "math.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFeatureAlgrithm::CFeatureAlgrithm()
{
}
CFeatureAlgrithm::~CFeatureAlgrithm()
{
}
//Canny算子提取全色图像的线特征
void CFeatureAlgrithm::CCanny(unsigned char *pUnchImage, int nWidth, int nHeight, double sigma,
double dRatioLow, double dRatioHigh, unsigned char *pUnchEdge)
{/*************************************************************************
*
* \函数名称:
* Canny()
* \输入参数:
* unsigned char *pUnchImage- 图象数据
* int nWidth - 图象数据宽度
* int nHeight - 图象数据高度
* double sigma - 高斯滤波的标准方差
* double dRatioLow - 低阈值和高阈值之间的比例
* double dRatioHigh - 高阈值占图象象素总数的比例
* unsigned char *pUnchEdge - canny算子计算后的分割图
*
* \返回值:
* 无
*
* \说明:
* canny分割算子,计算的结果保存在pUnchEdge中,逻辑1(255)表示该点为
* 边界点,逻辑0(0)表示该点为非边界点。该函数的参数sigma,dRatioLow
* dRatioHigh,是需要指定的。这些参数会影响分割后边界点数目的多少
*************************************************************************
*/
// 经过高斯滤波后的图象数据
unsigned char * pUnchSmooth ;
// 指向x方向导数的指针
int * pnGradX ;
// 指向y方向导数的指针
int * pnGradY ;
// 梯度的幅度
int * pnGradMag ;
pUnchSmooth = new unsigned char[nWidth*nHeight] ;
pnGradX = new int [nWidth*nHeight] ;
pnGradY = new int [nWidth*nHeight] ;
pnGradMag = new int [nWidth*nHeight] ;
// 对原图象进行滤波
GaussianSmooth(pUnchImage, nWidth, nHeight, sigma, pUnchSmooth) ;
// 计算方向导数
DirGrad(pUnchSmooth, nWidth, nHeight, pnGradX, pnGradY) ;
// 计算梯度的幅度
GradMagnitude(pnGradX, pnGradY, nWidth, nHeight, pnGradMag) ;
// 应用non-maximum 抑制
NonmaxSuppress(pnGradMag, pnGradX, pnGradY, nWidth, nHeight, pUnchEdge) ;
// 应用Hysteresis,找到所有的边界
Hysteresis(pnGradMag, nWidth, nHeight, dRatioLow, dRatioHigh, pUnchEdge);
// 释放内存
delete [] pnGradX ;
pnGradX = NULL ;
delete [] pnGradY ;
pnGradY = NULL ;
delete []pnGradMag ;
pnGradMag = NULL ;
delete []pUnchSmooth ;
pUnchSmooth = NULL ;
}
void CFeatureAlgrithm::GaussianSmooth(unsigned char *pUnchImg, int nWidth, int nHeight,double sigma, unsigned char * pUnchSmthdImg)
{
// 循环控制变量
int y;
int x;
int i;
// 高斯滤波器的数组长度
int nWindowSize;
// 窗口长度的1/2
int nHalfLen;
// 一维高斯数据滤波器
double *pdKernel ;
// 高斯系数与图象数据的点乘
double dDotMul ;
// 高斯滤波系数的总和
double dWeightSum ;
// 中间变量
double * pdTmp ;
// 分配内存
pdTmp = new double[nWidth*nHeight];
// 产生一维高斯数据滤波器
// MakeGauss(sigma, &dKernel, &nWindowSize);
MakeGauss(sigma, &pdKernel, &nWindowSize) ;
// MakeGauss返回窗口的长度,利用此变量计算窗口的半长
nHalfLen = nWindowSize / 2;
// x方向进行滤波
for(y=0; y<nHeight; y++)
{
for(x=0; x<nWidth; x++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nHalfLen); i<=nHalfLen; i++)
{
// 判断是否在图象内部
if( (i+x) >= 0 && (i+x) < nWidth )
{
dDotMul += (double)pUnchImg[y*nWidth + (i+x)] * pdKernel[nHalfLen+i];
dWeightSum += pdKernel[nHalfLen+i];
}
}
pdTmp[y*nWidth + x] = dDotMul/dWeightSum ;
}
}
// y方向进行滤波
for(x=0; x<nWidth; x++)
{
for(y=0; y<nHeight; y++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nHalfLen); i<=nHalfLen; i++)
{
// 判断是否在图象内部
if( (i+y) >= 0 && (i+y) < nHeight )
{
dDotMul += (double)pdTmp[(y+i)*nWidth + x] * pdKernel[nHalfLen+i];
dWeightSum += pdKernel[nHalfLen+i];
}
}
pUnchSmthdImg[y*nWidth + x] = (unsigned char)(int)(dDotMul/dWeightSum );
}
}
// 释放内存
delete []pdKernel;
pdKernel = NULL ;
delete []pdTmp;
pdTmp = NULL;
}
void CFeatureAlgrithm::MakeGauss(double sigma, double **pdKernel, int *pnWindowSize)
{
// 循环控制变量
int i ;
// 数组的中心点
int nCenter;
// 数组的某一点到中心点的距离
double dDis ;
double PI = 3.14159;
// 中间变量
double dValue;
double dSum ;
dSum = 0 ;
// 数组长度,根据概率论的知识,选取[-3*sigma, 3*sigma]以内的数据。
// 这些数据会覆盖绝大部分的滤波系数
*pnWindowSize = 1 + (int)(2 * ceil(3 * sigma));
// 中心
nCenter = (*pnWindowSize) / 2;
// 分配内存
*pdKernel = new double[*pnWindowSize] ;
for(i=0; i< (*pnWindowSize); i++)
{
dDis = (double)(i - nCenter);
dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma)) / (sqrt(2 * PI) * sigma );
(*pdKernel)[i] = dValue ;
dSum += dValue;
}
// 归一化
for(i=0; i<(*pnWindowSize) ; i++)
{
(*pdKernel)[i] /= dSum;
}
}
void CFeatureAlgrithm::DirGrad(unsigned char *pUnchSmthdImg, int nWidth, int nHeight,int *pnGradX , int *pnGradY)
{
// 循环控制变量
int y ;
int x ;
// 计算x方向的方向导数,在边界出进行了处理,防止要访问的象素出界
for(y=0; y<nHeight; y++)
{
for(x=0; x<nWidth; x++)
{
pnGradX[y*nWidth+x] = (int) ( pUnchSmthdImg[y*nWidth+min(nWidth-1,x+1)]
- pUnchSmthdImg[y*nWidth+max(0,x-1)] );
}
}
// 计算y方向的方向导数,在边界出进行了处理,防止要访问的象素出界
for(x=0; x<nWidth; x++)
{
for(y=0; y<nHeight; y++)
{
pnGradY[y*nWidth+x] = (int) ( pUnchSmthdImg[min(nHeight-1,y+1)*nWidth + x]
- pUnchSmthdImg[max(0,y-1)*nWidth+ x ] );
}
}
}
void CFeatureAlgrithm::GradMagnitude(int *pnGradX, int *pnGradY, int nWidth, int nHeight, int *pnMag)
{
/*\输入参数:
* int *pnGradX - x方向的方向导数
* int *pnGradY - y方向的方向导数
* int nWidht - 图象宽度
* int nHeight - 图象高度
* int *pnMag - 梯度幅度
* \说明:
* 这个函数利用方向倒数计算梯度幅度,方向倒数是DirGrad函数计算的结果*/
// 循环控制变量
int y ;
int x ;
// 中间变量
double dSqtOne;
double dSqtTwo;
for(y=0; y<nHeight; y++)
{
for(x=0; x<nWidth; x++)
{
dSqtOne = pnGradX[y*nWidth + x] * pnGradX[y*nWidth + x];
dSqtTwo = pnGradY[y*nWidth + x] * pnGradY[y*nWidth + x];
pnMag[y*nWidth + x] = (int)(sqrt(dSqtOne + dSqtTwo) + 0.5);
}
}
}
void CFeatureAlgrithm::NonmaxSuppress(int *pnMag, int *pnGradX, int *pnGradY, int nWidth,int nHeight, unsigned char *pUnchRst)
{
/* \输入参数:
* int *pnMag - 梯度图
* int *pnGradX - x方向的方向导数
* int *pnGradY - y方向的方向导数
* int nWidth - 图象数据宽度
* int nHeight - 图象数据高度
* unsigned char *pUnchRst - 经过NonmaxSuppress处理后的结果
\说明:
* 抑止梯度图中非局部极值点的象素。
*/
// 循环控制变量
int y ;
int x ;
int nPos;
// x方向梯度分量
int gx ;
int gy ;
// 临时变量
int g1, g2, g3, g4 ;
double weight ;
double dTmp1 ;
double dTmp2 ;
double dTmp ;
// 设置图象边缘部分为不可能的边界点
for(x=0; x<nWidth; x++)
{
pUnchRst[x] = 0 ;
pUnchRst[nHeight-1+x] = 0;
}
for(y=0; y<nHeight; y++)
{
pUnchRst[y*nWidth] = 0 ;
pUnchRst[y*nWidth + nWidth-1] = 0;
}
for(y=1; y<nHeight-1; y++)
{
for(x=1; x<nWidth-1; x++)
{
nPos = y*nWidth + x ;
// 如果当前象素的梯度幅度为0,则不是边界点
if(pnMag[nPos] == 0 )
{
pUnchRst[nPos] = 0 ;
}
else
{
// 当前象素的梯度幅度
dTmp = pnMag[nPos] ;
// x,y方向导数
gx = pnGradX[nPos] ;
gy = pnGradY[nPos] ;
// 如果方向导数y分量比x分量大,说明导数的方向更加“趋向”于y分量。
if (abs(gy) > abs(gx))
{
// 计算插值的比例
weight = fabs(gx)/fabs(gy);
g2 = pnMag[nPos-nWidth] ;
g4 = pnMag[nPos+nWidth] ;
// 如果x,y两个方向的方向导数的符号相同
// C是当前象素,与g1-g4的位置关系为:
// g1 g2
// C
// g4 g3
if (gx*gy > 0)
{
g1 = pnMag[nPos-nWidth-1] ;
g3 = pnMag[nPos+nWidth+1] ;
}
// 如果x,y两个方向的方向导数的符号相反
// C是当前象素,与g1-g4的位置关系为:
// g2 g1
// C
// g3 g4
else
{
g1 = pnMag[nPos-nWidth+1] ;
g3 = pnMag[nPos+nWidth-1] ;
}
}
// 如果方向导数x分量比y分量大,说明导数的方向更加“趋向”于x分量
// 这个判断语句包含了x分量和y分量相等的情况
else
{
// 计算插值的比例
weight = fabs(gy)/fabs(gx);
g2 = pnMag[nPos+1] ;
g4 = pnMag[nPos-1] ;
// 如果x,y两个方向的方向导数的符号相同
// C是当前象素,与g1-g4的位置关系为:
// g3
// g4 C g2
// g1
if (gx*gy > 0)
{
g1 = pnMag[nPos+nWidth+1] ;
g3 = pnMag[nPos-nWidth-1] ;
}
// 如果x,y两个方向的方向导数的符号相反
// C是当前象素,与g1-g4的位置关系为:
// g1
// g4 C g2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -