直方图均衡的C++实现方法

直方图均衡的C++实现方法

一. 原理

灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数,即 h ( k ) = n k ( k = 0 , 1 , , L 1 ) h(k)=n_k\quad (k=0,1,\cdots,L-1) ,其中 L L 为图像的灰度级数。

直方图均衡的目的是将图像的直方图修正为均匀分布形式(离散分布做不到完全均匀,但可以接近),增加像素灰度值的动态范围,从而达到增强图像对比度,提高清晰度的效果。

因而我们需要找到一种变换 t = E H ( s ) t=E_{\rm H}(s) 使得直方图变平直,且要使变换后的灰度仍保持从黑到白的单一变化顺序、变换范围与原先一致。同时规定:

  • 0 s 1 0\le s \le 1 E H ( s ) E_{\rm H}(s) 单调递增,且 0 E H ( s ) 1 0 \le E_{\rm H}(s) \le 1
  • 0 t 1 0\le t \le 1 ,其反变换 s = E H 1 ( t ) s = E^{-1}_{\rm H}(t) 单调递增。

具体方法如下:

  1. 设一幅图像的像素总数为 n n ,共有 L L 个灰度级, n k n_k 为第 k k 个灰度级出现的频率。则第 k k 个灰度级直方图均衡出现的概率为
    p ( s k ) = n k n p(s_k) = \dfrac {n_k} n

  2. 计算累计概率
    t k = E H ( s k ) = i = 0 k p ( s k ) , 0 t k 1 t_{k}=E_{\mathrm{H}}\left(s_{k}\right)=\sum_{i=0}^{k} p\left(s_{k}\right), \quad 0 \leq t_{k} \leq 1
    s s 的分布转换为 t t 的均匀分布;

  3. 将归一化的 t k t_k ,映射回灰度值区间 [ 0 , L 1 ] [0,L-1]
    t k = i n t [ ( L 1 ) t k + 0.5 ] t_k = {\rm int}\left[ (L-1)t_k+0.5 \right]
    其中加0.5再取整即为在程序中取四舍五入的算法;

  4. 对图像中每一个像素的灰度值进行映射,得到均衡后的图像。

下面将对seed.yuv进行直方图均衡。


原始图像

二. 实验代码

declarations.h

#pragma once
extern int w;
extern int h;

void Freq(unsigned char* yBuff, double freq[]);
void CumulativeFreq(double prob[], double cumProb[]);
void Mapping(double cumProb[], unsigned char* yBuffOri, unsigned char* yBuffEqu);

global.cpp

#include "declarations.h"
#include <iostream>

int w = 500;
int h = 500;

void Freq(unsigned char* yBuff, double prob[])
{
	double count[256] = { 0 };
	for (int i = 0; i < w * h; i++)
	{
		int greyIndex = (int)yBuff[i];
		count[greyIndex]++;
	}

	for (int i = 0; i < 256; i++)
	{
		prob[i] = count[i] / (w * h);
		//printf("%-5d%lf\n", i, prob[i]);
	}
}


void CumulativeFreq(double prob[], double cumProb[])
{
	cumProb[0] = 0;
	//printf("%-5d%lf\n", 0, cumProb[0]);

	for (int i = 1; i < 256; i++)
	{
		cumProb[i] = cumProb[i - 1] + prob[i - 1];
		//printf("%-5d%lf\n", i, cumProb[i]);
	}
}


void Mapping(double cumProb[], unsigned char* yBuffOri, unsigned char* yBuffEqu)
{
	for (int i = 0; i < 256; i++)
	{
		cumProb[i] = floor(255 * cumProb[i] + 0.5);
	}

	for (int i = 0; i < w * h; i++)
	{
		int greyIndex = (int)yBuffOri[i];
		yBuffEqu[i] = cumProb[greyIndex];
	}
}

main.cpp

#include <iostream>
#include "declarations.h"
using namespace std;

int main(int argc, char* argv[])
{
	FILE* oriImgPtr;
	FILE* equImgPtr;
	const char* oriImgName = argv[1];
	const char* equImgName = argv[2];
	double greyProb[256] = { 0 };
	double greyCumProb[256] = { 0 };

	/* Open the files */
	if (fopen_s(&oriImgPtr, oriImgName, "rb") == 0)
	{
		cout << "Successfully opened \"" << oriImgName << "\"." << endl;
	}
	else
	{
		cout << "Failed to open \"" << oriImgName << "\"." << endl;
		exit(-1);
	}
	if (fopen_s(&equImgPtr, equImgName, "wb") == 0)
	{
		cout << "Successfully opened \"" << equImgName << "\"." << endl;
	}
	else
	{
		cout << "Failed to open \"" << equImgName << "\"." << endl;
		exit(-1);
	}

	/* Space allocation */
	unsigned char* oriYBuff = new unsigned char[w * h];
	unsigned char* equYBuff = new unsigned char[w * h];
	unsigned char* equUBuff = new unsigned char[w * h / 4];
	unsigned char* equVBuff = new unsigned char[w * h / 4];
	int* greyFreq = new int[256];

	/* Initialisation of U & V component (greyscale image) */
	memset(equUBuff, 128, w * h / 4);
	memset(equVBuff, 128, w * h / 4);


	/* Read Y component into the buffer */
	fread(oriYBuff, sizeof(unsigned char), w * h, oriImgPtr);

	/* Calculate probabilities of each grey value */
	Freq(oriYBuff, greyProb);

	/* Calculate cumulative probabilites of each grey value */
	CumulativeFreq(greyProb, greyCumProb);

	/* Mapping */
	Mapping(greyCumProb, oriYBuff, equYBuff);

	/* Write histogram-equalised data into the new file */
	fwrite(equYBuff, sizeof(unsigned char), w * h, equImgPtr);
	fwrite(equUBuff, sizeof(unsigned char), w * h / 4, equImgPtr);
	fwrite(equVBuff, sizeof(unsigned char), w * h / 4, equImgPtr);

	delete[]oriYBuff;
	delete[]equYBuff;
	delete[]equUBuff;
	delete[]equVBuff;
  fclose(oriImgPtr);
  fclose(equImgPtr);
}

三. 实验结果

实验结果如下:


进行了直方图均衡后的图像

可以看到,相比原图,直方图均衡很好地实现了增强对比度、提高清晰度的功能。

发布了14 篇原创文章 · 获赞 3 · 访问量 3225

猜你喜欢

转载自blog.csdn.net/szzheng/article/details/105296889
今日推荐