【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

2023-11-08

       本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程《数字图像处理》及课件进行讲解,主要通过MFC单文档视图实现显示BMP图像增强处理,包括图像普通平滑、高斯平滑、不同算子的图像锐化知识。希望该篇文章对你有所帮助,尤其是初学者和学习图像处理的学生。
       【数字图像处理】一.MFC详解显示BMP格式图片
       【数字图像处理】二.MFC单文档分割窗口显示图片
       【数字图像处理】三.MFC实现图像灰度、采样和量化功能详解
       【数字图像处理】四.MFC对话框绘制灰度直方图
       【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
       【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解
        
免费资源下载地址:
        http://download.csdn.net/detail/eastmount/8785591

 

一. 图像增强简介

        图像增强是对图像进行处理,使其比原始图像更适合于特定的应用,它需要与实际应用相结合。对于图像的某些特征如边缘、轮廓、对比度等,图像增强是进行强调或锐化,以便于显示、观察或进一步分析与处理。图像增强的方法是因应用不同而不同的,研究内容包括:(参考课件和左飞的《数字图像处理》)

 

二. 图像平滑

        图像平滑是一种区域增强的算法,平滑算法有邻域平均法、中指滤波、边界保持类滤波等。在图像产生、传输和复制过程中,常常会因为多方面原因而被噪声干扰或出现数据丢失,降低了图像的质量(某一像素,如果它与周围像素点相比有明显的不同,则该点被噪声所感染)。这就需要对图像进行一定的增强处理以减小这些缺陷带来的影响。

       1.简单平滑-邻域平均法
        图像简单平滑是指通过邻域简单平均对图像进行平滑处理的方法,用这种方法在一定程度上消除原始图像中的噪声、降低原始图像对比度的作用。它利用卷积运算对图像邻域的像素灰度进行平均,从而达到减小图像中噪声影响、降低图像对比度的目的。
        但邻域平均值主要缺点是在降低噪声的同时使图像变得模糊,特别在边缘和细节处,而且邻域越大,在去噪能力增强的同时模糊程度越严重。

        2.高斯平滑
       
为了克服简单局部平均法的弊端(图像模糊),目前已提出许多保持边缘、细节的局部平滑算法。它们的出发点都集中在如何选择邻域的大小、形状和方向、参数加平均及邻域各店的权重系数等。
        图像高斯平滑也是邻域平均的思想对图像进行平滑的一种方法,在图像高斯平滑中,对图像进行平均时,不同位置的像素被赋予了不同的权重。
        在图像简单平滑中,算法利用卷积模板逐一处理图像中每个像素,这一过程可以形象地比作对原始图像的像素一一进行过滤整理,在图像处理中把邻域像素逐一处理的算法过程称为滤波器。平滑线性滤波器的工作原理是利用模板对邻域内像素灰度进行加权平均,也称为均值滤波器。
        高斯平滑与简单平滑不同,它在对邻域内像素进行平均时,给予不同位置的像素不同的权值,下图的所示的3*3和5*5领域的高斯模板。

        模板越靠近邻域中心位置,其权值越高。在图像细节进行模糊时,可以更多的保留图像总体的灰度分布特征。下图是常用的四个模板和matlab代码实现:

        代码如下:

I1 = imread('blood1.tif');
I=imnoise(I1,‘salt & pepper’,0.04);                %对图像加椒盐噪声
imshow(I);
h1= [0.1 0.1 0.1; 0.1 0.2 0.1; 0.1 0.1 0.1];        %定义4种模板
h2=1/16.*[1 2 1;2 4 2;1 2 1];
h3=1/8.*[1 1 1;1 0 1;1 1 1];
h4=1/2.*[0 1/4 0;1/4 1 1/4;0 1/4 0];
I2=filter2(h1,I);                                   %用4种模板进行滤波处理
I3=filter2(h2,I);
I4=filter2(h3,I);
I5=filter2(h4,I);
figure,imshow(I2,[])                                %显示处理结果
figure,imshow(I3,[])
figure,imshow(I4,[])
figure,imshow(I5,[])

        运行效果如下图所示:

        3.中值滤波
        在使用邻域平均法去噪的同时也使得边界变得模糊。而中值滤波是非线性的图像处理方法,在去噪的同时可以兼顾到边界信息的保留。
        选一个含有奇数点的窗口W,将这个窗口在图像上扫描,把窗口中所含的像素点按灰度级的升或降序排列,取位于中间的灰度值来代替该点的灰度值。

        例如选择滤波的窗口如下图,是一个一维的窗口,待处理像素的灰度取这个模板中灰度的中值,滤波过程如下:

        常用的窗口还有方形、十字形、圆形和环形。不同形状的窗口产生不同的滤波效果,方形和圆形窗口适合外轮廓线较长的物体图像,而十字形窗口对有尖顶角状的图像效果好。

        中值滤波对于消除孤立点和线段的干扰十分有用,尤其是对于二进噪声,但对消除高斯噪声的影响效果不佳。对于一些细节较多的复杂图像,可以多次使用不同的中值滤波。matlab实现参考:http://blog.csdn.net/timidsmile/article/details/6904381

        4.边界保持类滤波
        K近邻均值滤波器(KNNF)是指在m*m的窗口中,属于同一集合类的像素,它们的灰度值将高度相关。被处理的像素(对应于窗口中心的像素)可以用窗口内与中心像素灰度最接近的k个近邻像素的平均灰度来替代。步骤如下:
        (1).作一个m*m的作用模板
        (2).在其中选择K个与待处理像素的灰度差为最小的像素
        (3).用这K个像素的灰度均值替换掉原来的值

        在K近旁均值滤波器(KNNMF)中,不选K个邻近像素的平均灰度来替代,而选K个邻近像素的中值灰度来替代,上图中2,3,3中选择3即可。
        下面介绍具体MFC VC++6.0代码实现过程。

 

三. 图像平滑代码实现

        第一步:在资源视图的Menu中添加子菜单“图像增强”,然后添加“图像平滑”四个选项如下图所示:

        第二步:打开类向导,在ImageProcessingView类中添加相应的四个实现函数:

        第三步:就是具体的平滑实现函数。
        1.普通平滑 模板一
        该算法采用的模板如下:

        代码如下:

/**************************************************
  第九章--图像增强    
  图像平滑 普通平滑 模板
 
float H1[3][3]={{1.0/10,1.0/10,1.0/10}, //模板一:系数1/10
			   {1.0/10,2.0/10,1.0/10},
			   {1.0/10,1.0/10,1.0/10}};
		
float H2[3][3]={{1.0/16,2.0/16,1.0/16}, //模板二:系数1/16
			   {2.0/16,4.0/16,2.0/16},
			   {1.0/16,2.0/16,1.0/16}};

float H3[3][3]={{1.0/8,1.0/8,1.0/8},    //模板三:系数1/8,此种情况为把点转为空心矩形
			   {1.0/8,0.0/8,1.0/8},
			   {1.0/8,1.0/8,1.0/8}};

float H4[3][3]={{0.0,1.0/8,0.0},        //模板四:系数乘数据后的矩阵
			   {1.0/8,1.0/2,1.0/8},
			   {0.0,1.0/8,0.0}};

/**************************************************/


void CImageProcessingView::OnTxzqPtph1() 
{
	if(numPicture==0) {
		AfxMessageBox("载入图片后才能图像增强(平滑)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(平滑)!选取的模板为:普通平滑 模板一",MB_OK,0);

	/******************************************************************/
	/* 图想平滑的算法:                                               
	/*   1.定义常用的四个模板,它们的维数均为3,矩阵的个数均为9个数据   
	/*   2.它的思想是把一个点分散到这周围的9个点上,这样使图像更模糊   
	/*   3.通过卷积计算围绕该点的矩阵像素和,计算其平均值(除9)赋值给点 
	/*   4.模块不同,处理后的图像也各不相同                           
	/******************************************************************/

	/*第一步:先定义数据模板*/
	int HWS=3;                                //模板维数:此四个模板均为3维的
	float H1[3][3]={{1.0/10,1.0/10,1.0/10},   //模板一:系数1/10
					{1.0/10,2.0/10,1.0/10},
					{1.0/10,1.0/10,1.0/10}};
	
	//打开临时的图片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
    fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	//new和delete有效的进行动态内存的分配和释放
    unsigned char *ImageSize;        
    ImageSize = new unsigned char[m_nImage];    
	float red,green,blue;
	int X,Y;               //一维坐标转换为二维坐标
	int TR,TG,TB;          //记录红绿蓝坐标位置

	//图像增强:平滑 它要获取源图像周围9个点的矩阵乘以模板9个点的矩阵,故一维图像转二维
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		//原图:一维矩阵转换为二维矩阵
		X=(i/3)%m_nWidth;    //图像在X列
		Y=(i/3)/m_nWidth;    //图像在Y行

		//赋值为黑色,相当于清零
		red=green=blue=0;

		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )      //防止越界
				{			
					//模板一 进行模板平均,把该点像素分散到四周
					TR=j*m_nWidth*3+k*3;	
					red+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值
		ImageSize[i]=(unsigned char)(red);
		ImageSize[i+1]=(unsigned char)(green);
		ImageSize[i+2]=(unsigned char)(blue);
	}
		
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;
	Invalidate();
}

        运行效果如图所示,图像平滑模糊了,但效果不是很好。

        其中实现的具体原理如下:
        首先将图像像素矩阵转换为(X,Y)的二维矩阵进行操作,同时获取(X,Y)坐标为中心的3*3矩阵,再通过它与3*3模板进行像素平均操作,就是两个3*3矩阵互乘。需要注意的是矩阵一个格子是RGB三字节(24位BMP),同时获取该中心点位置时,通过两层循环for(k=n-1;k<=n+1;k++)实现获取矩阵中九个点的像素。最后对该点(X,Y)的RGB进行赋值操作即可。


       2.普通平滑 模板二
        该算法采用的模板如下:

        代码如下:

void CImageProcessingView::OnTxzqPtph2() 
{
	if(numPicture==0) {
		AfxMessageBox("载入图片后才能图像增强(平滑)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(平滑)!选取的模板为:普通平滑 模板二",MB_OK,0);

	/*第一步:先定义数据模板*/
	int HWS=3;
	float H2[3][3]={{1.0/8,1.0/8,1.0/8},    //模板三:系数1/8 此种情况为把点转为空心矩形
					{1.0/8,0.0/8,1.0/8},
					{1.0/8,1.0/8,1.0/8}};
	
	//打开临时的图片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
    fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	
	//重点:图像的每行像素都必须是4的倍数:1*1的图像为 r g b 00H   
	int num;            //记录每行多余的图像素数个数  
	int sfSize;         //补齐后的图像大小  
    if(m_nWidth*3%4!=0) {  
        num=(4-m_nWidth*3%4);  
        sfSize=(m_nWidth*3+num)*m_nHeight; //每行多number个  
    }  
    else {  
        num=0;  
        sfSize=m_nWidth*m_nHeight*3;  
    }  
  
    /*更改文件头信息 定义临时文件头结构变量*/  
    BITMAPFILEHEADER bfhsf;  
    BITMAPINFOHEADER bihsf;         
    bfhsf=bfh;  
    bihsf=bih;  
    bfhsf.bfSize=sfSize+54;  
    fwrite(&bfhsf,sizeof(BITMAPFILEHEADER),1,fpw);  
    fwrite(&bihsf,sizeof(BITMAPINFOHEADER),1,fpw);  
    fread(m_pImage,m_nImage,1,fpo);  

	//new和delete有效的进行动态内存的分配和释放
    unsigned char *ImageSize;        
    ImageSize = new unsigned char[sfSize];    
	float red,green,blue;
	int X,Y;               //一维坐标转换为二维坐标
	int TR,TG,TB;          //记录红绿蓝坐标位置  
    int countWidth=0;      //记录每行的像素个数,满行时变回0  
	int place=0;           //建立临时坐标 记录起始坐标(0,0)平移过来的位置 

	//图像增强 平滑
	for(int i=0; i<m_nImage; )
	{
		//原图一维矩阵转换为二维矩阵
		X=(i/3)%m_nWidth;    //图像在X列
		Y=(i/3)/m_nWidth;    //图像在Y行

		//赋值为黑色,相当于清零
		red=green=blue=0;

		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )      //防止越界
				{			
					//模板二 进行模板平均,把该点像素分散到四周
					TR=j*m_nWidth*3+k*3;	
					red+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值
		//通过变量place赋值变换后的图像 i始终指向原图3的倍数 为了补0而添加place变量
		ImageSize[place]=(unsigned char)(red);
		i++; place++;
		ImageSize[place]=(unsigned char)(green);
		i++; place++;
		ImageSize[place]=(unsigned char)(blue);
		i++; place++;
		countWidth=countWidth+3;
		
		if(countWidth==m_nWidth*3)    
        {    
			if(num==0)  
            {  
                countWidth=0;    
                place=Y*m_nWidth*3;
            }  
            else //num为补0  
            {  
                for(int n=0;n<num;n++)  
                {    
                    ImageSize[place]=0;  
					place++;  
                }  
                countWidth=0;   
                place=Y*(m_nWidth*3+num); //重点 添加Num  
            }  
		} 
	}
		
	fwrite(ImageSize,sfSize,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture=2;
	level=400;
	Invalidate();
}

        你可能注意到了,在图像处理过程中,如果每行的字节数不是4的倍数,可能会出现斜线之类的处理BUG,所以需要手动补0筹齐4的倍数,代码中补0后运行效果如下图所示,我也一直没找到原因,可能是思想和深度还没有达到,以后有机会在解决吧!同时后面的算法都不准备再进行补0处理,主要讲述算法的思想!

         3.高斯平滑
         采用的模板如下:

        代码如下图所示:

//高斯平滑
void CImageProcessingView::OnTxzqGsph() 
{
	if(numPicture==0) {
		AfxMessageBox("载入图片后才能图像增强(平滑)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(平滑)!选取的模板为:高斯平滑",MB_OK,0);

	/*第一步:先定义数据模板*/
	int HWS=3;                                //模板维数为3维
	float H[3][3]={{1.0/16,2.0/16,1.0/16},    //高斯模板 系数1/16
				   {2.0/16,4.0/16,2.0/16},
				   {1.0/16,2.0/16,1.0/16}};
	
	//打开临时的图片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
    fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	//new和delete有效的进行动态内存的分配和释放
    unsigned char *ImageSize;        
    ImageSize = new unsigned char[m_nImage];    
	float red,green,blue;
	int X,Y;               //一维坐标转换为二维坐标
	int TR,TG,TB;          //记录红绿蓝坐标位置

	//图像增强:平滑 
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		//原图:一维矩阵转换为二维矩阵
		X=(i/3)%m_nWidth;    //图像在X列
		Y=(i/3)/m_nWidth;    //图像在Y行

		//赋值为黑色,相当于清零
		red=green=blue=0;

		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )      //防止越界
				{			
					//模板二 进行模板平均,把该点像素分散到四周
					TR=j*m_nWidth*3+k*3;	
					red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值
		ImageSize[i]=(unsigned char)(red);
		ImageSize[i+1]=(unsigned char)(green);
		ImageSize[i+2]=(unsigned char)(blue);
	}
		
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;
	Invalidate();
}

        运行效果如下图所示:

        4.中值滤波
        中值滤波我的理解是:它不但可以去除孤点噪声,而且可以保持图像的边缘特性,不会产生显著的模糊;它的方法是把局部区域的像素按灰度等级进行排序,再取该邻域中灰度的中值作为当前像素的灰度值。其步骤如下:
        (1).将滤波模板(含若干个点的滑动窗口)在图像中漫游,并将模板中心与图像中的某个像素位置重合;
        (2).读取模板中各对应像素的灰度值;
        (3).将这些灰度值从小到大排序;
        (4).取这一列数据的中间数据,将其赋值给对应模板中心位置的像素。

        我采用的是3*3的模本,取矩阵中间位置像素替代原像素。代码如下:

//中值滤波
void CImageProcessingView::OnTxzqZzlb() 
{
	if(numPicture==0) {
		AfxMessageBox("载入图片后才能图像增强(平滑)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(平滑)!选取的模板为:中值滤波",MB_OK,0);

	//打开临时的图片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
    fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	//new和delete有效的进行动态内存的分配和释放
    unsigned char *ImageSize;        
    ImageSize = new unsigned char[m_nImage];    
	int X,Y;               //一维坐标转换为二维坐标
	int TR,TG,TB;          //记录红绿蓝坐标位置

	//选取它为中心的周围9个点像素(注意一个点为RGB)
	int H[9]={0,0,0,0,0,0,0,0,0};    
	int HWS=3;             //维数为三维

	//图像增强:平滑 它要获取源图像周围9个点的矩阵乘以模板9个点的矩阵,故一维图像转二维
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		//原图:一维矩阵转换为二维矩阵
		X=(i/3)%m_nWidth;    //图像在X列
		Y=(i/3)/m_nWidth;    //图像在Y行
		
		//第一行 第一列 最后一行 最后一列 直接复制
		if(X==0 || Y==0 || X==m_nWidth*3 || Y==m_nHeight) 
		{
			if(i+2>m_nImage) break;
			ImageSize[i] = m_pImage[i];
			ImageSize[i+1] = m_pImage[i+1];
			ImageSize[i+2] = m_pImage[i+2];
			continue;
		}

		//对图像进行像素求和并取平均值 HWS维数
		int num=0;
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )      //防止越界
				{			
					//获取当前位置Red像素 k一次增加RGB三个像素 R=G=B
					TR = j*m_nWidth*3+k*3;	
					H[num] = m_pImage[TR];
					num++;
				}
			}
		}
		//排序获取中间值
		int temp=0;
		for(int x=0;x<9;x++)
		{
			for(int y=x;y<9;y++)
			{
				if(H[x]>=H[y])
				{
					temp=H[x];
					H[x]=H[y];
					H[y]=temp;
				}
			}
		}
		//CString str;
		//str.Format("矩阵:%d %d %d, %d %d %d, %d %d %d",H[0],H[1],H[2],H[3],H[4],H[5],H[6],H[7],H[8]);
		//AfxMessageBox(str);

		//对新图像赋值 灰度图像RGB相同
		ImageSize[i]=H[4];
		ImageSize[i+1]=H[4];
		ImageSize[i+2]=H[4];
	}
		
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;
	Invalidate();
}

        运行效果如下图所示:

        PS:这部分总算讲述完成,算法都是根据自己的理解用底层代码实现的,而不是向其它的通过调用GDI+库实现。可能存在因为理解不够或其它的错误,欢迎提出修改~
        推荐资料:
        图像平滑处理——OpenCV         数字图像处理学习笔记——图像平滑锐化 
        中值滤波    

 

四. 图像锐化

       有时还需要加强图像中景物的边缘和轮廓,边缘和轮廓通常位于图像中灰度突出的地方,因而可以直观的想到用灰度的差分对边缘和轮廓进行提取,通常可以通过梯度算子进行提取。图像锐化的目的是提高图像的对比度,从而使图像更清晰,通过提高邻域内像素的灰度差来提高图像的对比度。
       下面介绍图像锐化的几种算子及效果。
        1.拉普拉斯算子(Laplacian)
        拉普拉斯算子是图像邻域内像素灰度差分计算的基础,通过二阶微分推导出的一种图像邻域增强算法。它的基本思想是当邻域的中心像素灰度低于它所在邻域内的其他像素的平均灰度时,此中心像素的灰度应该被进一步降低;当高于时进一步提高中心像素的灰度,从而实现图像锐化处理。
        在算法实现过程中,通过对邻域中心像素的四方向或八方向求梯度,并将梯度和相加来判断中心像素灰度与邻域内其他像素灰度的关系,并用梯度运算的结果对像素灰度进行调整。
        一个连续的二元函数f(x,y),其拉普拉斯运算定义为:

        对于数字图像,拉普拉斯算子可以简化为:

        也可以表示为卷积的形式:

        其中K=1,I=1时H(r,s)取下式,四方向模板:

        通过模板可以发现,当邻域内像素灰度相同时,模板的卷积运算结果为0;当中心像素灰度高于邻域内其他像素的平均灰度时,模板的卷积运算结果为正数;当中心像素的灰度低于邻域内其他像素的平均灰度时,模板的卷积为负数。对卷积运算的结果用适当的衰弱因子处理并加在原中心像素上,就可以实现图像的锐化处理。
        其中实现过程步骤如下:
        添加子菜单和类向导添加实现函数

        代码如下:

/*****************************************/
/* 图像锐化:我在menu中创建5个子的menu    */
/* 防止出现平滑错误,一次只调用一个下拉单 */
/* ID_RH_Laplacian Laplacian拉普拉斯算子 */
/* ID_RH_Sobel Sobel算子                 */
/* ID_RH_Prewitt Prewitt算子             */
/* ID_RH_Isotropic Isotropic算子         */
/* ID_RH_GTMB 高通模板H2                 */
/*****************************************/

void CImageProcessingView::OnRHLaplacian() 
{
	if(numPicture==0) 
	{
		AfxMessageBox("载入图片后才能图像增强(锐化)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(锐化):采用拉普拉斯(Laplacian)算子!");

	//模板维数:此四个模板均为3维的
	int HWS=3;  
	int H[3][3]={{0,-1,0},    //模板为拉普拉斯算子(中心为4的Laplacian)
				{-1,4,-1},
				{0,-1,0}};

	//读写文件
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	//new和delete有效的进行动态内存的分配和释放
	unsigned char *ImageSize;      
	ImageSize=new unsigned char[m_nImage];  
	int red,green,blue;
	int X,Y;       //一维坐标转换为二维坐标
	int TR,TG,TB;  //记录红绿蓝坐标位置
	
	//图像增强 锐化
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		X=(i/3)%m_nWidth;    //X列
		Y=(i/3)/m_nWidth;    //Y行
		red=green=blue=0;
		
		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )
				{			
					
					TR=j*m_nWidth*3+k*3;	
					red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值
		if(red>=0 && red<256) ImageSize[i]=red;
		else if(red<0) ImageSize[i]=0;      //ImageSize[i]=-red;
		else ImageSize[i]=0;
		
		if(green>=0 && green<256) ImageSize[i+1]=green;
		else if(green<0) ImageSize[i+1]=0;  //ImageSize[i+1]=-green;
		else ImageSize[i+1]=0;
		
		if(blue>=0 && blue<256) ImageSize[i+2]=blue;
		else if(blue<0) ImageSize[i+2]=0;   //ImageSize[i+2]=-blue;
		else ImageSize[i+2]=0;
	}
	
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;	
	Invalidate();
}

        运行效果如下图所示:


        2.高通滤波
        常用的高通模板如下所示,其中H2有的书又称为拉普拉斯八方向的锐化模板。

        选取H2模板,代码如下所示:

//高通模板
void CImageProcessingView::OnRhGtmb() 
{
	if(numPicture==0)
	{
		AfxMessageBox("载入图片后才能图像增强(锐化)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(锐化):采用高通模板!");

	int HWS=3;                                
	int H[3][3]={{-1,-1,-1},    
				{-1,8,-1},
				{-1,-1,-1}};

	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	unsigned char *ImageSize;      
	ImageSize=new unsigned char[m_nImage];  
	int red,green,blue;
	int X,Y;       
	int TR,TG,TB; 
	
	//图像增强 锐化
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		X=(i/3)%m_nWidth;    //X列
		Y=(i/3)/m_nWidth;    //Y行
		red=green=blue=0;
		
		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )
				{			
					
					TR=j*m_nWidth*3+k*3;	
					red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);
				}
			}
		}
		
		//对新图像赋值
		if(red>=0 && red<256) ImageSize[i]=red;
		else if(red<0) ImageSize[i]=0;      //ImageSize[i]=-red;
		else ImageSize[i]=0;
		
		if(green>=0 && green<256) ImageSize[i+1]=green;
		else if(green<0) ImageSize[i+1]=0;  //ImageSize[i+1]=-green;
		else ImageSize[i+1]=0;
		
		if(blue>=0 && blue<256) ImageSize[i+2]=blue;
		else if(blue<0) ImageSize[i+2]=0;   //ImageSize[i+2]=-blue;
		else ImageSize[i+2]=0;
	}
	
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;	
	Invalidate();	
}

        运行效果如下图所示,该效果相对较好:

 


       3.Sobel算子

        代码如下所示,需要注意X和Y两个方向的模板处理:

//Sobel算子采用PPT上的d(x)d(y)模板
void CImageProcessingView::OnRHSobel() 
{
	if(numPicture==0)
	{
		AfxMessageBox("载入图片后才能图像增强(锐化)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(锐化):采用Sobel算子!");

	int HWS=3;                                
	//模板为Sobel算子
	int HX[3][3]={{1,0,-1},{2,0,-2},{1,0,-1}};
	int HY[3][3]={{-1,-2,-1},{0,0,0},{1,2,1}};

	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);	
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	unsigned char *ImageSize;      
	ImageSize=new unsigned char[m_nImage];  
	int redX,greenX,blueX;
	int redY,greenY,blueY;
	int X,Y;       
	int TR,TG,TB;  
	
	//图像增强 锐化
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		X=(i/3)%m_nWidth;    //X列
		Y=(i/3)/m_nWidth;    //Y行
		redX=greenX=blueX=0;
		redY=greenY=blueY=0;
		
		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )
				{			
					
					TR=j*m_nWidth*3+k*3;	
					redX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);
					redY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					greenX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);
					greenY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blueX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);
					blueY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);
				}
			}
		}
		//s=(d(x)*d(x)+d(y)*d(y))开根号
		int R,G,B;
		R=(int)(sqrt(redX*redX*1.0+redY*redY*1.0));
		G=(int)(sqrt(greenX*greenX*1.0+greenY*greenY*1.0));
		B=(int)(sqrt(blueX*blueX*1.0+blueY*blueY*1.0));

		if(redX<0 && redY<0) ImageSize[i]=0;
		else if(R>255) ImageSize[i]=255;
		else ImageSize[i]=R;
		
		if(greenX<0 && greenY<0) ImageSize[i+1]=0;
		else if(G>255) ImageSize[i+1]=255;
		else ImageSize[i+1]=G;

		if(blueX<0 && blueY<0) ImageSize[i+2]=0;
		else if(B>255) ImageSize[i+2]=255;
		else ImageSize[i+2]=B;
	}
	
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;	
	Invalidate();
}

        运行效果如下图所示:

        如果采用Sobel边缘细化,建议二值化(0和255阈值化)处理后再锐化,彩色图建议先灰度处理再进行其他处理。


      4.Isotropic算子
 

        代码实现如下:

//Isotropic算子采用PPT上的d(x)模板 d(y)
void CImageProcessingView::OnRHIsotropic() 
{
	if(numPicture==0)
	{
		AfxMessageBox("载入图片后才能图像增强(锐化)!",MB_OK,0);
		return;
	}

	AfxMessageBox("图像增强(锐化):采用Isotropic算子!");

	int HWS=3;                               
	//模板为Isotropic算子
	float HX[3][3]={{1,0,-1},
					{sqrt(2.0),0,-sqrt(2.0)}, 
					{1,0,-1} };
	float HY[3][3]={{-1,-sqrt(2.0),-1},
					{0,0,0}, 
					{1,sqrt(2.0),1} };

	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	unsigned char *ImageSize;      
	ImageSize=new unsigned char[m_nImage];  
	float redX,greenX,blueX;
	float redY,greenY,blueY;
	int X,Y;      
	int TR,TG,TB;  
	
	//图像增强
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		X=(i/3)%m_nWidth;    //X列
		Y=(i/3)/m_nWidth;    //Y行
		redX=greenX=blueX=0;
		redY=greenY=blueY=0;
		
		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )
				{			
					
					TR=j*m_nWidth*3+k*3;	
					redX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);
					redY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					greenX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);
					greenY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blueX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);
					blueY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值 s=(d(x)*d(x)+d(y)*d(y))开根号
		int R,G,B;
		R=(int)(sqrt(redX*redX*1.0+redY*redY*1.0));
		G=(int)(sqrt(greenX*greenX*1.0+greenY*greenY*1.0));
		B=(int)(sqrt(blueX*blueX*1.0+blueY*blueY*1.0));

		if(redX<0 && redY<0) ImageSize[i]=0;
		else if(R>255) ImageSize[i]=255;
		else ImageSize[i]=R;
		
		if(greenX<0 && greenY<0) ImageSize[i+1]=0;
		else if(G>255) ImageSize[i+1]=255;
		else ImageSize[i+1]=G;

		if(blueX<0 && blueY<0) ImageSize[i+2]=0;
		else if(B>255) ImageSize[i+2]=255;
		else ImageSize[i+2]=B;
	}
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;	
	Invalidate();
}

        运行效果如下图所示,效果与上面的Sobel类似:


       5.Prewitt算子

        代码如下图所示:

//Prewitt算子采用PPT上的d(x)模板,不是d(y)
void CImageProcessingView::OnRHPrewitt() 
{
	
	if(numPicture==0)
	{
		AfxMessageBox("载入图片后才能图像增强(锐化)!",MB_OK,0);
		return;
	}
	AfxMessageBox("图像增强(锐化):采用Prewitt算子!");

	int HWS=3;                               
	int H[3][3]={{1,0,-1},    //模板为Prewitt算子
				{1,0,-1},
				{1,0,-1}};

	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	fread(m_pImage,m_nImage,1,fpo);

	unsigned char *ImageSize;      
	ImageSize=new unsigned char[m_nImage];  
	int red,green,blue;
	int X,Y;      
	int TR,TG,TB; 
	
	//图像增强:平滑
	for(int i=0; i<m_nImage ; i=i+3 )
	{
		X=(i/3)%m_nWidth;    //X列
		Y=(i/3)/m_nWidth;    //Y行
		red=green=blue=0;
		
		//对图像进行像素求和并取平均值 HWS维数
		for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ )                      //第j行
		{
			for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ )                  //第k列
			{
				if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight )
				{			
					
					TR=j*m_nWidth*3+k*3;	
					red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);
					TG=j*m_nWidth*3+k*3+1;
					green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);
					TB=j*m_nWidth*3+k*3+2;
					blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);
				}
			}
		}
		//对新图像赋值
		if(red>=0 && red<256) ImageSize[i]=red;
		else if(red<0) ImageSize[i]=0;      //ImageSize[i]=-red;
		else ImageSize[i]=0;
		
		if(green>=0 && green<256) ImageSize[i+1]=green;
		else if(green<0) ImageSize[i+1]=0;  //ImageSize[i+1]=-green;
		else ImageSize[i+1]=0;
		
		if(blue>=0 && blue<256) ImageSize[i+2]=blue;
		else if(blue<0) ImageSize[i+2]=0;   //ImageSize[i+2]=-blue;
		else ImageSize[i+2]=0;	
	}
	fwrite(ImageSize,m_nImage,1,fpw);  
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=400;	
	Invalidate();
}

        运行效果如下图所示,只选取了X分量:

        最后还是希望文章对你有所帮助,如果文章有不足或错误之处,请海涵。自己给自己点个赞,挺不容易的,但还会继续写完~同时后面的图像处理准备研究些感兴趣的东西,而不是这样的长篇大论了,例如怎样实现验证码提取、如何实现图像恢复、DICOM图像等知识吧!

      (By:Eastmount 2015-06-08 下午6点   http://blog.csdn.net/eastmount/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解 的相关文章

  • MFC 将 CMFCToolBar 按钮更改为切换而不是按下/释放?

    我在网上找到一篇文章 说将工具栏按钮设置为保持按下的类型 只需设置一个样式TBBS CHECKBOX在按钮上 但它对我不起作用 它仍然像普通按钮一样工作 我确认样式已设置 在创建之后SetWindowText MFC 向导设置CMainFr
  • Visual Studio 无法识别我的网络摄像头激光测距仪代码的 MFC 库

    我尝试直接从互联网复制源代码 但由于下面发现的错误 我无法构建 调试整个文件 请帮忙 Error occurred while restoring NuGet packages System ArgumentException The pa
  • MFC> 将对话框连接到对话框类

    我在现有的资源文件中定义了一个新对话框及其控件 我还创建了一个新文件 它将处理从此对话框生成的事件 但我不确定如何连接这两者 是声明enum IDD IDD NEW DIALOG 连接两者所需的一切 或者我们应该添加一些其他声明 在 MFC
  • dll 中的 MFC LoadString 失败

    我在 dll 中有一个静态函数 它使用 LoadString 从资源加载字符串 当我从该 dll 调用此函数时 一切正常 但是 当我从其他模块 activeX 控件 调用此函数时 LoadString 失败并出现错误 ERROR RESOU
  • 菜单被裁剪

    我有一个MFC项目 它支持 40 多种语言 我的电脑上有两个显示器 它们都是不同尺寸的显示器和不同的分辨率 如果我将应用程序移至较小的显示器上 则不会显示完整的语言菜单 我知道它会显示滚动条 为什么不是呢 我的菜单是标准菜单 没有什么花哨
  • 托管和非托管 C++/MFC 可以混合在一个 dll 中吗?

    以前 我们有 MFC VC6 VB6 和 C 应用程序中的软件 需要调用用 C 和 MFC 编写的相同引擎 该引擎需要 C 来提高速度 当时我们决定使用 COM 作为接口 因为所有三个都可以使用它 并且在编组等方面的问题最少 我们的 MFC
  • GetWindowRect 坐标不与屏幕相关

    我正在使用 Visual Studio 2008 C 工作 我有一个 MFC 对话框 里面有一个控件 我正在尝试在控件中放置另一个对话框 第二个对话框上的 SetWindowPos 显然使用屏幕坐标 因此我需要获取控件或父对话框的屏幕坐标
  • Boost::序列化和 MFC Doc/View 架构

    我正在移植现有的 MFC C 应用程序以对 XML 文件使用 Boost Serialization 我的 CDocument 对象包含应用程序的所有数据 我已将序列化函数实现为 template
  • 如何将 std::variant 作为 VARIANT* 传递给 ExecWB?

    我看过这篇关于使用的文章std variant https en cppreference com w cpp utility variant 这是因为以下代码引发了代码分析警告 void CChristianLifeMinistryHtm
  • 如何在 MFC 中创建 GUI

    我需要能够即时创建指南 MFC中有没有办法做到这一点 我了解了如何在 net 中做到这一点 但我们还没有做到这一点 如果没有 您是否有一些我可以使用的代码的指针 don t forget to add Rpcrt4 lib to your
  • 与 UltraHD 兼容的 CHtmlView

    CHtmlView与 UltraHD 分辨率不兼容 实现 UltraHD 感知并不仅仅在于使用正确的 HTML CSS 打印预览机制失败并裁剪页面 许多个月前 微软承认这是一个问题 但没有解决它 我的应用程序大量使用CHtmlView用于显
  • 编辑默认工具栏时 Microsoft Visual Studio“未知位图格式”

    我已使用项目创建向导使用 Microsoft 基础类库 MFC 创建了一个应用程序 我创建了一个多文档界面 MDI 应用程序 该向导创建您可以使用的虚拟工具栏和菜单 我扩展了默认工具栏 没有任何问题 但是现在当我尝试通过资源视图编辑它时 我
  • 如何找到激活时打开给定 HMENU 的菜单项(如果有)?

    我想用原型实现一个功能 Locates the menu item of the application which caused the given menu mnu to show up return true if the given
  • 如何将命名管道字符串从非托管代码空间发送到托管代码空间?

    我似乎遇到了命名管道 101 问题 我有一个非常简单的设置来连接从 C 非托管应用程序传输到 C 托管应用程序的单工命名管道 管道已连接 但我无法通过管道发送 消息 除非我关闭似乎刷新缓冲区并传递消息的句柄 就好像消息被屏蔽了一样 我尝试颠
  • 如何通过单击 MainFrame 内的按钮来更改 MFC 视图

    我想通过单击窗口内的按钮来更改呈现的视图像这样 https i stack imgur com 3IA2o png 我的项目设置 我制作了一个没有文档 视图支持的 MFC 项目 SDI 我在设计器中又创建了两个视图并向它们添加了类 新的视图
  • MinGW支持MFC吗?

    我已经使用 MinGW 开发了 WinAPI 应用程序 没有出现任何问题 现在 我可以用 MFC 做同样的事情吗 我只是在这里猜测 但我认为您需要购买 Visual Studio 的副本才能获得使用 MFC 的许可证 MFC 也不因其对 C
  • 对 MFC UI 应用程序进行单元测试吗?

    如何对大型 MFC UI 应用程序进行单元测试 我们有一些大型 MFC 应用程序已经开发了很多年 我们使用一些标准的自动化 QA 工具来运行基本脚本来检查基础知识 文件打开等 这些由 QA 小组在日常构建后运行 但我们希望引入一些程序 以便
  • C++ 检查 unicode 字符是否为全角

    如何检查unicode字符是否是全角 我使用Win32 MFC 例如 中是全宽 A不是全角 是全宽 F不是全宽 你需要的是检索东亚宽度 http www unicode org reports tr11 的角色 您可以通过解析来做到这一点东
  • 如何通过MFC将应用程序设置保存到注册表中?

    我有一个由 MFC 项目向导创建的 MFC 应用程序 我想在注册表中保存 读取应用程序设置 所以问了这个question https stackoverflow com questions 1880275 good c registry w
  • 具有键唯一性和按位置排序的 MFC 字典集合

    看着表上http msdn microsoft com en us library y1z022s1 28v vs 80 29 aspx core collection shape features http msdn microsoft

随机推荐

  • 关注 OpenStack 的筒子们,福利来啦!

    2017 OpenStack Days China 将于 2017 年 7 月 24 日 25 日 周一至周二 在北京国家会议中心隆重召开 我们非常荣幸能和大家一起见证并打造这样一个强有力的 大规模的云计算标准软件平台 这一次 OpenSt
  • 如何在MarkDown文件中插入Emoji表情?

    如何在MarkDown文件中插入Emoji表情 解决方法 markdown语法的目的是使用户专注于文本内容编辑 在双手不离开键盘的情况下也能对页面进行排版编辑 提高内容书写的效率和可读性 如果在文档中添加一些符号表情 也能为文本增添一些趣味
  • 如何通过JDBC连接远程服务端的数据库

    如何通过JDBC连接远程服务端的数据库 1 本地navicat链接到远程服务端 2 Myeclipse创建JDBC 1 本地navicat链接到远程服务端 首先 打开远程服务器 远程数据库中新建查询 输入SQL语句 表示允许任何主机访问数据
  • 【Uniapp】一、 UniAPP框架基本信息

    1 什么是 UniAPP uni app 是一个使用 Vue js 开发所有前端应用的框架 开发者编写一套代码 可发布到 iOS Android H5 以及各种小程序 微信 支付宝 百度 头条 QQ 钉钉 等多个平台 uni app在手 做
  • 【实际开发21】- 项目部署

    目录 1 项目打包方式就两种 war jar 1 Windows 环境运行 Jar 包 2 Windows 后台运行 jar 包 1 cmd 下执行方式 2 bat 批处理方式 Batch 3 启动 在 xx jar 同级目录下建立 run
  • 114.114.114.114和8.8.8.8两者联系与区别

    联系 114 114 114 114 和 8 8 8 8 这两个IP地址都属于公共域名解析服务DNS其中的一部分 而且由于不是用于商业用途的 这两个DNS都很纯净 不用担心因ISP运营商导致的DNS劫持等问题 而且都是免费提供给用户使用的
  • 【编程笔试】美团2021校招笔试-通用编程题第8场(附思路及C++代码)

    导览 练习地址 小美的书架 偏爱字母 搭配出售 十字路口 练习地址 点此前往练习 小美的书架 小美的书架上有很多书 小美是个爱读书的新时代好青年 小团虽然也喜欢看书 但小团大多数时候都更喜欢来小美家蹭书读 这就导致小美的书架上很多书都会被小
  • 区块链-为什么区块链是不可篡改的

    目录 https blog csdn net qq 40452317 article details 89646633 区块链的数据结构是由包含交易信息的区块按照从远及近的顺序有序链接起来的 区块被从远及近有序地链接在这个链条里 每个区块都
  • python 多元回归参数输出_python-如何从statsmodels中的WLS回归的2D参数获...

    我使用statsmodels递增了WLS regression functions的参数 我有一个这样声明的10 3数据集X X np array 1 2 3 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 1 2 3 4 5
  • HTML学习篇

    基于HBuild 综合训练1 img src img 666 jpg title width 200 height 300 border 5 br a href work1 跳转锚点 a a href class1 html target
  • Spring Cache缓存技术的介绍

    缓存用于提升系统的性能 特别适用于一些对资源需求比较高的操作 本文介绍如何基于spring boot cache技术 使用caffeine作为具体的缓存实现 对操作的结果进行缓存 demo场景 本demo将创建一个web应用 提供两个Res
  • 科大讯飞版ChatGPT提前内测!附申请方法

    讯飞 星火 认知大模型是科大讯飞版的 ChatGPT 在内测阶段 目前已经开放内测申请 它可以学习和理解人类语言 进行多轮对话 回答问题并帮助人们快速获取知识和灵感 可用于写作诗歌 歌词 故事 代码和表格等 并能够分析逻辑问题 解决数学题及
  • 【Bootstrap】Bootstrap添加时间选择器组件datetimepicker

    文章目录 Bootstrap Bootstrap添加时间选择器组件datetimepicker 一 引入bootstrap基础库 二 引入bootstrap datetimepicker库 三 使用方法 四 一些问题 Bootstrap B
  • 企业为什么要上云?企业上云的好处和优势有哪些

    企业上云是比较热门的话题也是趋势 越来越多的企业放弃传统IDC选择上云 新手站长网告诉你企业为什么要上云 企业上云的好处和优势有哪些 企业为什么要上云 企业上云也是企业集成发展的趋势 国内外很多企业相继投入了云的怀抱 诸如飞利浦关闭中国数据
  • 大数据毕设项目 机器学习餐厅销量预测 -大数据 python

    文章目录 0 前言 餐厅销量预测 一 建模流程 二 模型简介 2 ARIMA模型介绍 2 1自回归模型AR 2 2移动平均模型MA 2 3自回归移动平均模型ARMA 三 模型识别 四 模型检验 4 1半稳性检验 1 用途 1 什么是平稳序列
  • uni-app中小数变成整数,开方

    保留整数部分 会转化成1 parseInt 1 6 舍去小数部分 会转化成1 Math floor 1 6 小数部分进位 会转化成2 Math ceil 1 6 四舍五入 1 6 gt 2 1 4 gt 1 Math round 1 6 3
  • 线程学习--pthread--锁链及条件变量

    pthread cond wait函数的使用 一般跟lock一起用 pthread mutex lock mutex pthread cond wait cond mutex 等待条件变量满足 把获得的锁释放掉 注意 1 2两步是一个原子操
  • Unity利用OpenCV人脸识别库实现2D真人换装

    软件开发插件 OpenCv DlibFaceLandmarkDetector FaceMaskExample 对此有疑问可以访问前两篇文章 Unity版本为2018 4 36 有技术的可以自己封装一下获取摄像头的函数 反正我不会 用的Ope
  • mAP的计算方法

    侵删 转载于 https blog csdn net hysteric314 article details 54093734 摘要 在训练YOLO v2的过程中 系统会显示出一些评价训练效果的值 如Recall IoU等等 为了怕以后忘了
  • 【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

    本文主要讲述基于VC 6 0 MFC图像处理的应用知识 主要结合自己大三所学课程 数字图像处理 及课件进行讲解 主要通过MFC单文档视图实现显示BMP图像增强处理 包括图像普通平滑 高斯平滑 不同算子的图像锐化知识 希望该篇文章对你有所帮助