mathmorphology.cpp
来自「visual c++数字图像与图形处理中的光盘内容」· C++ 代码 · 共 1,035 行 · 第 1/2 页
CPP
1,035 行
/////////////////////////////////////////////////////////////////////////////////
//
// MathMorphology.cpp: implementation of the CMathMorphology class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming
#include "stdafx.h"
#include "MathMorphology.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CMathMorphology, CImageProcess)
CMathMorphology::CMathMorphology()
{
m_dwOperation = IMAGE_MATH_MORPHOLOGY_DILATE;
m_nElementUsed = 1;
m_pME = NULL;
}
CMathMorphology::~CMathMorphology()
{
if(m_pME)delete[] m_pME;
m_pME = NULL;
}
#ifdef _DEBUG
void CMathMorphology::Dump(CDumpContext& dc) const
{
CImageProcess::Dump(dc);
}
void CMathMorphology::AssertValid() const
{
CImageProcess::AssertValid();
}
#endif
//nEUsed----pME数组的大小
void CMathMorphology::SetMorphologyElement(const MORPHOLOGYELEMENT* pME, int nEUsed)
{
ASSERT(pME);
m_nElementUsed = nEUsed;
if(m_pME) delete[] m_pME;
m_pME = new MORPHOLOGYELEMENT[nEUsed];
for(int i = 0;i < m_nElementUsed;i++) m_pME[i] = pME[i];
}
//数学形态学--膨胀
//lpbyBits32----源像素值, 带回结果值
//x, y, nWidth, int nHeight, 定义区域的宽度
//nScanWidth, int nScanHeight, 扫描宽度和扫描高度
BOOL CMathMorphology::Dilate(LPBYTE lpbyBits32, int x, int y, int nWidth, int nHeight, int nScanWidth, int nScanHeight)
{
//第一步, 进行参数合法性检测
ASSERT(lpbyBits32);
ASSERT(m_pME);
if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
m_dwOperation = IMAGE_MATH_MORPHOLOGY_DILATE;
//有效区域的宽度和高度
int w = min(nWidth, nScanWidth - x);
int h = min(nHeight, nScanHeight - y);
//第二步, 分配内存空间, 最后结果只可能在(-255, +255)之间,
//存储蓝色、绿色、红色
int nSize = w * h;
//注:避免分配大的存储空间的办法是引入结构元素的分解算法
//我们这里采用分配大的内存来实现,从而使算法很直观
//比如, 对于800 * 600的图像
//2 = sizeof(short);
//800 * 600 * 2 * 3 + 800 * 600 * 2 * 3 = 5760000 bytes
//存储源
short* pcxDataSrc = new short[(nSize * 3)];
if (pcxDataSrc == NULL) return FALSE;
//存储目标
short* pcxDataDst = new short[(nSize * 3)];
if (pcxDataDst == NULL) return FALSE;
//第三步, 获取输入图像的数据
//行字节数
DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
//开始数据基索引
DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
//指向内存源数据
short* pcxDataFore = pcxDataSrc;
int i, j;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
//blue
*pcxDataFore++ = *pbySrc++;
//green
*pcxDataFore++ = *pbySrc++;
//red
*pcxDataFore++ = *pbySrc++;
pbySrc++;
}
dwBaseIndex += dwWidthBytes;
}
//第四步, 进行膨胀, 这是主要的计算工作
Dilate(pcxDataSrc, w, h, pcxDataDst);
//第五步, 回带数据
//指向内存目标数据
pcxDataFore = pcxDataDst;
dwBaseIndex = y * dwWidthBytes + 4 * x;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
short cxBlue = *pcxDataFore++;
short cxGreen = *pcxDataFore++;
short cxRed = *pcxDataFore++;
*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
pbyDst++;
}
dwBaseIndex += dwWidthBytes;
}
delete[] pcxDataSrc;
delete[] pcxDataDst;
return TRUE;
}
//膨胀----保护成员函数
void CMathMorphology::Dilate(short* pcxDataSrc, int nWidth, int nHeight, short* pcxDataDst)
{
//指向返回数据区
short* pcxDst = pcxDataDst;
//行数据
int nRowScan = 3 * nWidth;
for(int i = 0;i < nHeight;i++)
{
for(int j = 0;j < nWidth;j++)
{
//移动结构元素至(i, j)点
short cxMaxRed, cxMaxGreen, cxMaxBlue;
cxMaxRed = cxMaxGreen = cxMaxBlue = -32767;
for(int k = 0;k < m_nElementUsed;k++)
{
//基于结构元素的相对坐标
int xr = m_pME[k].x;
int yr = m_pME[k].y;
//绝对地址
int x = j - xr;
int y = i - yr;
//注意形态学膨胀运算的原始定义是, 只要有一个相交即可
//但是, 为了避免边界处可能没有进行处理, 而使结果看起来有些缺陷,
//我们简单地将边界进行复制
x = (x < 0) ? 0 : ((x > (nWidth - 1)) ? (nWidth - 1) : x);
y = (y < 0) ? 0 : ((y > (nHeight - 1)) ? (nHeight - 1) : y);
//获取数据
short cxBlue = pcxDataSrc[(y * nRowScan + 3 * x)];
short cxGreen = pcxDataSrc[(y * nRowScan + 3 * x + 1)];
short cxRed = pcxDataSrc[(y * nRowScan + 3 * x + 2)];
short cxB = cxBlue + m_pME[k].blue;
short cxG = cxGreen + m_pME[k].green;
short cxR = cxRed + m_pME[k].red;
if(cxB > cxMaxBlue)cxMaxBlue = cxB;
if(cxG > cxMaxGreen)cxMaxGreen = cxG;
if(cxR > cxMaxRed)cxMaxRed = cxR;
}
//由于我们将边界扩大, 因而总是可以重叠的
/*
cxMaxBlue = BOUND(cxMaxBlue, 0, 255);
cxMaxGreen = BOUND(cxMaxGreen, 0, 255);
cxMaxRed = BOUND(cxMaxRed, 0, 255);
*/
pcxDataDst[(i * nRowScan + 3 * j)] = cxMaxBlue;
pcxDataDst[(i * nRowScan + 3 * j + 1)] = cxMaxGreen;
pcxDataDst[(i * nRowScan + 3 * j + 2)] = cxMaxRed;
}
}
}
//腐蚀----公有成员函数
BOOL CMathMorphology::Erode(LPBYTE lpbyBits32, int x, int y, int nWidth, int nHeight, int nScanWidth, int nScanHeight)
{
//第一步, 进行参数合法性检测
ASSERT(lpbyBits32);
ASSERT(m_pME);
if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
m_dwOperation = IMAGE_MATH_MORPHOLOGY_ERODE;
//有效区域的宽度和高度
int w = min(nWidth, nScanWidth - x);
int h = min(nHeight, nScanHeight - y);
//第二步, 分配内存空间, 结果只可能在(-255, +255)之间,
//存储蓝色、绿色、红色
int nSize = w * h;
//存储源
short* pcxDataSrc = new short[(nSize * 3)];
if (pcxDataSrc == NULL) return FALSE;
//存储目标
short* pcxDataDst = new short[(nSize * 3)];
if (pcxDataDst == NULL) return FALSE;
//第三步, 获取输入图像的数据
//行字节数
DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
//开始数据基索引
DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
//指向内存源数据
short* pcxDataFore = pcxDataSrc;
int i, j;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
//blue
*pcxDataFore++ = *pbySrc++;
//green
*pcxDataFore++ = *pbySrc++;
//red
*pcxDataFore++ = *pbySrc++;
pbySrc++;
}
dwBaseIndex += dwWidthBytes;
}
//第四步
//进行腐蚀, 这是主要的计算工作
Erode(pcxDataSrc, w, h, pcxDataDst);
//第五步
//指向内存目标数据
pcxDataFore = pcxDataDst;
dwBaseIndex = y * dwWidthBytes + 4 * x;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
short cxBlue = *pcxDataFore++;
short cxGreen = *pcxDataFore++;
short cxRed = *pcxDataFore++;
*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
pbyDst++;
}
dwBaseIndex += dwWidthBytes;
}
delete[] pcxDataSrc;
delete[] pcxDataDst;
return TRUE;
}
//腐蚀----保护成员函数
void CMathMorphology::Erode(short *pcxDataSrc, int nWidth, int nHeight, short *pcxDataDst)
{
//指向返回数据区
short* pcxDst = pcxDataDst;
//行数据
int nRowScan = 3 * nWidth;
for(int i = 0;i < nHeight;i++)
{
for(int j = 0;j < nWidth;j++)
{
//移动结构元素至(i, j)点
short cxMinRed, cxMinGreen, cxMinBlue;
cxMinRed = cxMinGreen = cxMinBlue = 32767;
for(int k = 0;k < m_nElementUsed;k++)
{
//基于结构元素的相对坐标
int xr = m_pME[k].x;
int yr = m_pME[k].y;
//绝对地址
int x = j + xr;
int y = i + yr;
//注意形态学腐蚀运算的原始定义是, 所有相交才进行腐蚀,
//但是, 为了避免边界处可能没有进行处理, 而使结果看起来有些缺陷,
//我们简单地将边界进行复制
x = (x < 0) ? 0 : ((x > (nWidth - 1)) ? (nWidth - 1) : x);
y = (y < 0) ? 0 : ((y > (nHeight - 1)) ? (nHeight - 1) : y);
//获取数据
short cxBlue = pcxDataSrc[(y * nRowScan + 3 * x)];
short cxGreen = pcxDataSrc[(y * nRowScan + 3 * x + 1)];
short cxRed = pcxDataSrc[(y * nRowScan + 3 * x + 2)];
short cxB = cxBlue - m_pME[k].blue;
short cxG = cxGreen - m_pME[k].green;
short cxR = cxRed - m_pME[k].red;
if(cxB < cxMinBlue)cxMinBlue = cxB;
if(cxG < cxMinGreen)cxMinGreen = cxG;
if(cxR < cxMinRed)cxMinRed = cxR;
}//end
/*
cxMinBlue = BOUND(cxMinBlue, 0, 255);
cxMinGreen = BOUND(cxMinGreen, 0, 255);
cxMinRed = BOUND(cxMinRed, 0, 255);
*/
pcxDataDst[(i * nRowScan + 3 * j)] = cxMinBlue;
pcxDataDst[(i * nRowScan + 3 * j + 1)] = cxMinGreen;
pcxDataDst[(i * nRowScan + 3 * j + 2)] = cxMinRed;
}//end j
}//end i
}
//形态学开启
BOOL CMathMorphology::Open(LPBYTE lpbyBits32, int x, int y, int nWidth, int nHeight, int nScanWidth, int nScanHeight)
{
//第一步, 进行参数合法性检测
ASSERT(lpbyBits32);
ASSERT(m_pME);
if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
m_dwOperation = IMAGE_MATH_MORPHOLOGY_OPEN;
//有效区域的宽度和高度
int w = min(nWidth, nScanWidth - x);
int h = min(nHeight, nScanHeight - y);
//第二步, 分配内存空间, 结果只可能在(-255, +255)之间,
//存储蓝色、绿色、红色
int nSize = w * h;
//存储源
short* pcxDataSrc = new short[(nSize * 3)];
if (pcxDataSrc == NULL) return FALSE;
//存储目标
short* pcxDataDst = new short[(nSize * 3)];
if (pcxDataDst == NULL) return FALSE;
//第三步, 获取输入图像的数据
//行字节数
DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
//开始数据基索引
DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
//指向内存源数据
short* pcxDataFore = pcxDataSrc;
int i, j;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
//blue
*pcxDataFore++ = *pbySrc++;
//green
*pcxDataFore++ = *pbySrc++;
//red
*pcxDataFore++ = *pbySrc++;
pbySrc++;
}
dwBaseIndex += dwWidthBytes;
}
//第四步
//先进行腐蚀, 然后进行膨胀
Erode(pcxDataSrc, w, h, pcxDataDst);
Dilate(pcxDataDst, w, h, pcxDataSrc);
//第五步
//指向内存目标数据
pcxDataFore = pcxDataSrc;
dwBaseIndex = y * dwWidthBytes + 4 * x;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
short cxBlue = *pcxDataFore++;
short cxGreen = *pcxDataFore++;
short cxRed = *pcxDataFore++;
*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
pbyDst++;
}
dwBaseIndex += dwWidthBytes;
}
delete[] pcxDataSrc;
delete[] pcxDataDst;
return TRUE;
}
//关闭
BOOL CMathMorphology::Close(LPBYTE lpbyBits32, int x, int y, int nWidth, int nHeight, int nScanWidth, int nScanHeight)
{
//第一步, 进行参数合法性检测
ASSERT(lpbyBits32);
ASSERT(m_pME);
if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
m_dwOperation = IMAGE_MATH_MORPHOLOGY_CLOSE;
//有效区域的宽度和高度
int w = min(nWidth, nScanWidth - x);
int h = min(nHeight, nScanHeight - y);
//第二步, 分配内存空间, 结果只可能在(-255, +255)之间,
//存储蓝色、绿色、红色
int nSize = w * h;
//存储源
short* pcxDataSrc = new short[(nSize * 3)];
if (pcxDataSrc == NULL) return FALSE;
//存储目标
short* pcxDataDst = new short[(nSize * 3)];
if (pcxDataDst == NULL) return FALSE;
//第三步, 获取输入图像的数据
//行字节数
DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
//开始数据基索引
DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
//指向内存源数据
short* pcxDataFore = pcxDataSrc;
int i, j;
for(i = 0;i < h;i++)
{
//指向一行的开始数据
BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
for(j = 0;j < w;j++)
{
//blue
*pcxDataFore++ = *pbySrc++;
//green
*pcxDataFore++ = *pbySrc++;
//red
*pcxDataFore++ = *pbySrc++;
pbySrc++;
}
dwBaseIndex += dwWidthBytes;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?