当前位置:   article > 正文

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

直方图均衡 c++

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

一. 原理

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

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

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

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

具体方法如下:

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

  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 tk=EH(sk)=i=0kp(sk),0tk1
    s s s的分布转换为 t t t的均匀分布;

  3. 将归一化的 t k t_k tk,映射回灰度值区间 [ 0 , L − 1 ] [0,L-1] [0,L1]
    t k = i n t [ ( L − 1 ) t k + 0.5 ] t_k = {\rm int}\left[ (L-1)t_k+0.5 \right] tk=int[(L1)tk+0.5]
    其中加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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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];
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

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];
	int greyFreq[256] = { 0 };
	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];

	/* 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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

三. 实验结果

实验结果如下:


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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/78931
推荐阅读
相关标签
  

闽ICP备14008679号