前两篇文章处理的都是8位灰度图,这篇文章处理的是24位真彩色图(bmp),它们之间的不同主要是8位灰度图有调色板,一个像素占一个字节,而24位真彩色图是一个像素占3个字节,分别是BGR三个通道(存储的顺序为BGR),因此在将算法从8位灰度图转移到24位真彩色图时,只需要对BGR三个通道分别处理即可。
下面是实现代码:
一、24位真彩色图二维卷积高斯模糊,边缘已处理,无黑边(效果在后面)
/*************************************************************************
*
* 函数名称:
* GaussSmooth2D24()
*
* 参数:
* LPSTR lpDIBBits - 指向源DIB图像指针
* LONG lWidth - 源图像宽度(象素数)
* LONG lHeight - 源图像高度(象素数)
* float fSigma - 方差
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数对24位位图进行高斯模糊(2维高斯模糊)。
*
************************************************************************/
BOOL WINAPI GaussSmooth2D24(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, float fSigma)
{
//指向高斯数据数组的指针,用作储存一维数组首元素的地址的地址
float *fArray2D;
// 数组的某一点到中心点的距离
LONG iDistanceX;
LONG iDistanceY;
//模板高度
int iTempH;
//模板宽度
int iTempW;
//模板的中心元素X坐标 ( < iTempW - 1)
int iTempMX;
//模板的中心元素Y坐标 ( < iTempY - 1)
int iTempMY;
//π值
double dPI = 3.1415926536;
// 中间变量
double dValue;
double dSum = 0;
// 数组长度,根据概率论的知识,选取[-3*sigma, 3*sigma]以内的数据。
// 这些数据会覆盖绝大部分的滤波系数
iTempH = 1 + 2 * ceil(3 * fSigma); //ceil()返回大于或等于指定表达式的最小整数
iTempW = 1 + 2 * ceil(3 * fSigma); //ceil()返回大于或等于指定表达式的最小整数
iTempMX = (int)iTempW / 2;
iTempMY = (int)iTempH / 2;
// 分配内存
fArray2D = new float[iTempH*iTempW];
for (int i = 0; i < iTempH; i++)
{
for (int j = 0; j < iTempW; j++)
{
iDistanceY = abs(i - (int)(iTempH / 2));
iDistanceX = abs(j - (int)(iTempW / 2));
double aa = -0.5 / (fSigma*fSigma);
double bb = -aa / dPI;
dValue = bb*exp(aa*(iDistanceX*iDistanceX + iDistanceY*iDistanceY));
//dValue = exp(-(1 / 2)*(iDistanceX*iDistanceX + iDistanceY*iDistanceY)/ dSigma*dSigma) / (2 * dPI*dSigma*dSigma);
(fArray2D)[i*iTempH + j] = dValue;
dSum += dValue;
}
}
// 归一化
for (int i = 0; i < iTempH; i++)
{
for (int j = 0; j < iTempW; j++)
{
(fArray2D)[i*iTempH + j] /= dSum;
}
}
// 指向源图像的指针
unsigned char* lpSrc;
// 计算结果
FLOAT fResult1, fResult2, fResult3;
// 图像每行的字节数
LONG lLineBytes;
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(lWidth * 24);
//定义暂时存储图像数组
int* buf;
buf = new int[(lHeight + iTempMY * 2) * (lWidth + iTempMX * 2) * 3];
unsigned char* lpRed;
unsigned char* lpGreen;
unsigned char* lpBlue;
//把图像复制给buf数组,并且把边缘也复制给buf数组,这样buf的大小就为(lHeight + iTempMY * 2) * (lWidth + iTempMX * 2) * 3
for (int i = 0; i < lHeight; i++)
{
for (int j = 0; j < lWidth * 3; j++)
{
//扫描方式为从左到右,从下到上方式
lpSrc = (unsigned char*)lpDIBBits + lLineBytes*(lHeight - 1 - i) + j;
buf[(i + iTempMY)*(lWidth + iTempMX * 2) * 3 + iTempMX * 3 + j] = *lpSrc;
}
}
//复制图像上方iTempMY*3行(1)
for (int i = 0; i < iTempMY; i++)
{
for (int j = 0; j < lWidth * 3; j++)
{
//扫描方式为从左到右,从下到上方式
lpSrc = (unsigned char*)lpDIBBits + lLineBytes*(lHeight - 1 - i) + j;
buf[i*(lWidth + iTempMX * 2) * 3 + iTempMX * 3 + j] = *lpSrc;
}
}
//复制图像下方iTempMY*3行(2)
for (int i = lHeight - iTempMY; i < lHeight; i++)
{
for (int j = 0; j < lWidth * 3; j++)
{
//扫描方式为从左到右,从下到上方式
lpSrc = (unsigned char*)lpDIBBits + lLineBytes*(lHeight -