图像处理知识点3:灰度变换与直方图均衡化(C++)

        对于灰度变换与直方图均衡化都是图像增强经常用到的方法,方法原理与解释在这里就不做过多的叙述,本算法都是正常的传统算法没有进行算法优化过的,之前在说过针对算法优化本人也在学习,最近本人忙着找工作可能更新的少,有时间就会更新吧。废话不多说,直接上代码。

1.第一部分:图像读写

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include<iostream>
#include<assert.h>
#include<vector>
#define WIDTHBYTES(bits) (((bits)+31)/32*4)

using namespace std;

BYTE* Read8BitBmpFile2Img(const char* filename, int* width, int* height)
{
	FILE* BinFile;
	BITMAPFILEHEADER FileHeader;
	BITMAPINFOHEADER BmpHeader;
	BYTE* plmg;
	unsigned int size;
	int Suc = 1, w, h;

	//open file
	*width = *height = 0;
	if ((BinFile = fopen(filename, "rb")) == NULL) return NULL;
	//read struct info
	if (fread((void*)&FileHeader, 1, sizeof(FileHeader), BinFile) != sizeof(FileHeader)) Suc = -1;
	if (fread((void*)&BmpHeader, 1, sizeof(BmpHeader), BinFile) != sizeof(BmpHeader)) Suc = -1;
	if ((Suc == -1) || (FileHeader.bfOffBits < sizeof(FileHeader) + sizeof(BmpHeader)))
	{
		fclose(BinFile);
		return NULL;
	}
	//read Image data
	*width = w = BmpHeader.biWidth;
	*height = h = BmpHeader.biHeight;
	size = w * h;
	fseek(BinFile, FileHeader.bfOffBits, SEEK_SET);
	if ((plmg = new BYTE[size]) != NULL)
	{
		for (int i = 0; i < h; i++)  //0,1,2,3,4(5);400-499
		{
			if (fread(plmg + (h - 1 - i) * w, sizeof(BYTE), w, BinFile) != w)
			{
				fclose(BinFile);
				delete plmg;
				plmg = NULL;
				return NULL;
			}
			fseek(BinFile, (w + 3) / 4 * 4 - w, SEEK_CUR);
		}
	}
	fclose(BinFile);
	return plmg;
}

bool Write8BitImg2BmpFile(BYTE* pImg, int width, int height, const char* filename)
//当宽度不是4的倍数时自动添加成4的倍数
{
	FILE* BinFile;
	BITMAPFILEHEADER FileHeader;
	BITMAPINFOHEADER BmpHeader;
	int i, extend;
	bool Suc = true;
	BYTE p[4], * pCur;

	//Open File
	if ((BinFile = fopen(filename, "w+b")) == NULL) { return false; }
	//Fill the FileHeader
	FileHeader.bfType = ((WORD)('M' << 8) | 'B');
	FileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * 4L;
	FileHeader.bfSize = FileHeader.bfOffBits + width * height;
	FileHeader.bfReserved1 = 0;
	FileHeader.bfReserved2 = 0;
	if (fwrite((void*)&FileHeader, 1, sizeof(FileHeader), BinFile) != sizeof(FileHeader)) Suc = false;
	//Fill the ImgHeader
	BmpHeader.biSize = 40;
	BmpHeader.biWidth = width;
	BmpHeader.biHeight = height;
	BmpHeader.biPlanes = 1;
	BmpHeader.biBitCount = 8;
	BmpHeader.biCompression = 0;
	BmpHeader.biSizeImage = 0;
	BmpHeader.biXPelsPerMeter = 0;
	BmpHeader.biYPelsPerMeter = 0;
	BmpHeader.biClrUsed = 0;
	BmpHeader.biClrImportant = 0;
	if (fwrite((void*)&BmpHeader, 1, sizeof(BmpHeader), BinFile) != sizeof(BmpHeader)) Suc = false;
	//write Pallete
	for (i = 0, p[3] = 0; i < 256; i++)
	{
		p[3] = 0;
		p[0] = p[1] = p[2] = i;//blue,green,red
		if (fwrite((void*)p, 1, 4, BinFile) != 4) { Suc = false; break; }
	}
	//write image data
	extend = (width + 3) / 4 * 4 - width;
	if (extend == 0)
	{
		for (pCur = pImg + (height - 1) * width; pCur >= pImg; pCur -= width)
		{
			if (fwrite((void*)pCur, 1, width, BinFile) != (unsigned int)width) Suc = false;//真实的数据
		}
	}
	else
	{
		for (pCur = pImg + (height - 1) * width; pCur >= pImg; pCur -= width)
		{
			if (fwrite((void*)pCur, 1, width + 1, BinFile) != (unsigned int)width) Suc = false;//真实的数据
			for (i = 0; i < extend; i++)//扩充的数据
				if (fwrite((void*)(pCur + width - 1), 1, 1, BinFile) != 1) Suc = false;
		}
	}
	//return
	fclose(BinFile);
	return Suc;
}

2.第二部分:图像数据处理之灰度变换

2.1取反

void fanzhun(unsigned char* inputImg, unsigned char* outputImg, int width, int height)
{
	    for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				outputImg[i * width + j] = 255 - inputImg[i * width + j];
				
			}
			           
	    }
}

2.2(对数变换)s = clog(1 + r)  c为常数,本次测试中c取10

void logarithm(unsigned char* inputImg, unsigned char* outputImg, int width, int height)
{
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
	      outputImg[i * width + j] = (unsigned char)(10 * log((1 + inputImg[i * width + j])));
		}
			
	}
}

2.3(伽马变换)s = crγ  其中 c 和 γ 为正常数.(其中γ<1时,降低对比度,γ>1时,提高对比度)

void gamma(unsigned char* inputImg, unsigned char* outputImg, int width, int height)
{
	for (int i = 0; i < height; i++) 
	{
		for (int j = 0; j < width; j++)
		{
			outputImg[i * width + j] = (unsigned char)pow(inputImg[i * width + j], 1.05);

			outputImg[i * width + j] = outputImg[i * width + j] < 255 ? outputImg[i * width + j] : 255;

			
		}
			
	}
}

3.第三部分:直方图均衡化

void  EqualizeHist(unsigned char* inputImg, unsigned char* outputImg, int width, int height)
{
	int gray[256] = { 0 };               //记录每个灰度级别下的像素个数
	double gray_prob[256] = { 0 };          //记录灰度分布密度
	double gray_distribution[256] = { 0 };      //记录累计密度
	int gray_equal[256] = { 0 };              //均衡化后的灰度值

	int gray_sum = height * width;                         //像素总数

	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			gray[(int)inputImg[i*width+j]]++;      //记录每个灰度级下的像素个数,一共255个灰度级。开辟了整形一维整形一维数组。
		}
	}

	for (int i = 0; i < 256; i++)
	{
		gray_prob[i] = ((double)gray[i] / gray_sum);     //记录灰度分布密度,每个灰度级的像素数占整个图像的比例。
	}

	gray_distribution[0] = gray_prob[0];

	for (int i = 1; i < 256; i++)
	{
		gray_distribution[i] = gray_distribution[i - 1] + gray_prob[i];
	}
	for (int i = 0; i < 256; i++)
	{
		gray_equal[i] = (unsigned char)(255 * gray_distribution[i] );      //均衡化后的灰度值
	}
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			outputImg[i*width+j] = gray_equal[(int)inputImg[i * width + j]];     //灰度映射
		}
	}
}

4.主函数部分

int main()
{
	int width, height, func = 0, threshold = 0;
	clock_t startTime, endTime;
	startTime = clock();       //计时开始
	char readPath[] = "D:\\机器视觉学习工程\\lianxi\\me.bmp";
	BYTE* pGryImg = Read8BitBmpFile2Img(readPath, &width, &height);        //注意:下面对应位置也要该改名。

	BYTE* dstImg = new BYTE[width * height];

	memset(dstImg, 0, width * height*sizeof(unsigned char));
	printf("%d,%d\n", width, height);

	//EqualizeHist(pGryImg, dstImg, width, height);

	//guidingHist(pGryImg, dstImg, width, height);

	//fanzhun(pGryImg, dstImg, width, height);

	//logarithm(pGryImg, dstImg, width, height);

	//gamma(pGryImg, dstImg, width, height);

	//histogram_equalization(pGryImg, dstImg, width, height);


	cout << "操作完成" << endl;
	char writePath[] = "D:\\机器视觉学习工程\\lianxi\\mejunzhi.bmp";
	Write8BitImg2BmpFile(dstImg, width, height, writePath);
	ShellExecuteA(nullptr, "open", writePath, "", "", SW_SHOW);     //打开写入的位图结果

	endTime = clock();    //计时结束
	cout << "The run time is: " << (float)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	delete[] dstImg;
	delete[] pGryImg;
}

结束语:本代码写的有点次,都是传统的写法,还需要很多优化。比如遍历图象数据通过遍历首尾地址就可以了,我这样遍历有点慢,而且一些乘除法用移位的方式进行计算也能提高算法速度,还有之前的高斯滤波可以变成两个一维进行计算。嗯,那先这样吧。稍后继续再写一章。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值