简单

行远必自迩,登高必自卑

提取图像直方图(图像处理)

继直方图规定化后的研究

由于直方图规定化是根据两张图片的累计直方图进行图像的处理。对于这个处理过程,我尝试了很图像进行替换色系,但是没有找到一个相对合适案例,来体现直方图规定化这个算法的精妙之处。在多次尝试中,我发现一个灰度图像(原图)和一个彩色图像(规定化图)进行直方图规定化处理后,就会得到一个彩色的图像。

我的发现

我们都知道,灰度图像转换为彩色图形,一般情况下都是假彩色。如何将一个灰度图像进行还原成原本的彩色图像,那就是我们需要获得彩色图像的直方图。

创新之处

我利用彩色图像,生成一个色条,该色条与宽度无关。也就是说,我用 1 个像素宽,n 个像素长的有颜色的色条,就可以储存该图像的直方图。通过该色条与一张灰度图像,使用直方图规定化算法就可以将彩色图像还原出来。

具体的用处

  1. 一种新的图像储存方式,使得图像的存储空间更小。
  2. 作为直方图规定化的后续研究提供另一种思路。
  3. 解决一些需要由灰度图像转换为彩色图像的便捷方式。

图像说明

使用程序可以将图像的直方图提取出来,显示到图片下面,如图所示。

原图及直方图色条显示

源码

///////////////////////////////////////////////////
// 程序名称:图像处理——提取直方图
// 编译环境:Mictosoft Visual Studio 2013, EasyX_20200315(beta)
// 作    者:luoyh <2864292458@qq.com>
// 学    校:河南理工大学
// 最后修改:2021-11-21
//

#include<graphics.h>
#include<conio.h>
#include<math.h>

// 计算每一种 DN 值在整个像片中所占的比例
void Hist(IMAGE *pimg, double num[][256])
{
	DWORD *p = GetImageBuffer(pimg);
	for (int j = 0; j < 256; j++)
	{
		double sumr = 0.0;
		double sumg = 0.0;
		double sumb = 0.0;
		for (int i = pimg->getwidth() * pimg->getheight() - 1; i >= 0; i--)
		{
			if (j == GetRValue(p[i]))
			{
				sumr++;
			}
			if (j == GetGValue(p[i]))
			{
				sumg++;
			}
			if (j == GetBValue(p[i]))
			{
				sumb++;
			}
		}
		num[0][j] = sumr / (pimg->getwidth() * pimg->getheight());
		num[1][j] = sumg / (pimg->getwidth() * pimg->getheight());
		num[2][j] = sumb / (pimg->getwidth() * pimg->getheight());
	}
}

// 累计直方图
void HistTOsum(double Hist[][256], int Sum[][256])
{
	for (int j = 0; j < 3; j++)
	{
		double mysum = 0;
		for (int i = 0; i < 256; i++)
		{
			mysum += Hist[j][i];
			Sum[j][i] = (int)mysum;
		}
	}
}

int main()
{
	int	width = 0;
	int	height = 0;
	IMAGE imgpolt, imgTM;
	loadimage(&imgpolt, _T("bingbing.jpeg"));		// 加载原图
	width = imgpolt.getwidth();
	height = imgpolt.getheight();
	initgraph(width, height + 30);
	setbkcolor(WHITE);
	cleardevice();
	putimage(0, 0, &imgpolt);

	double HistPO[3][256];						// 原图像的频率
	int HistPOsum[3][256];						// 原累计直方图

	Hist(&imgpolt, HistPO);						// 计算原图的直方图

	for (int i = 0; i < 256; i++)
	{
		HistPO[0][i] = HistPO[0][i] * width;
		HistPO[1][i] = HistPO[1][i] * width;
		HistPO[2][i] = HistPO[2][i] * width;
	}

	HistTOsum(HistPO, HistPOsum);				// 计算原图的累计直方图

	for (int x = 0; x < width; x++)
	{
		int r = 0, g = 0, b = 0;
		bool Isr = true;
		bool Isg = true;
		bool Isb = true;
		for (int j = 0; j < 256; j++)
		{
			if (x <= HistPOsum[0][j] && Isr)
			{
				r = j;
				Isr = false;
			}
			if (x <= HistPOsum[1][j] && Isg)
			{
				g = j;
				Isg = false;
			}
			if (x <= HistPOsum[2][j] && Isb)
			{
				b = j;
				Isb = false;
			}
			if (Isr == false && Isg == false && Isb == false)
			{
				// 颜色在内存中的表示形式为:0xbbggrr (bb=蓝,gg=绿,rr=红),但是显存中的颜色表现形式为 0xrrggbb。 
				// 所要特别注意这里两者的红色和蓝色是相反的。
				setlinecolor(RGB(b, g, r));
				line(x, height, x, height + 30);
				break;
			}
		}
	}
	setfillcolor(RED);
	bar(0, height - 20, 140, height);
	setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 4);
	setlinecolor(RED);
	settextcolor(WHITE);
	settextstyle(25, 0, L"微软雅黑", 0, 0, 0, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH);
	line(0, height, width, height);
	line(0, height + 28, width, height + 28);
	setbkmode(TRANSPARENT);
	outtextxy(0, height - 20, _T("颜色直方图色条"));
	_getch();
	return 0;
}
分享到

添加评论