数字图像处理基本算法实现(1)--section3.2基本灰度变换

          虽然学的是与图像处理有关的专业,也看过一些图像处理的书,基本的算法原理也懂,但是一直以来都是用现成的库,没有自己按照算法编过,或者有些算法照着别人的代码敲一遍,什么也没学到,所以一直就想好好补补,试着自己去按照算法描述编一下,不管效率,允许小的bug,只是去学习一下,然后与别人的更好的实现对比一下,找找差距。这也快毕业要去工作了,趁着现在有点时间,就试着做一下,不知道能坚持到什么地步,不管怎样,尽力而为了。

        以冈萨雷斯的《数字图像处理(第三版)》为参考文献,使用VS2008,结合OpenCV中的一些函数,当然尽量不用现成的函数,只是用OpenCV的读取,保存,显示图像等。

      第一次,从3.2节开始:

头文件

class section_3_2
{
public:
	Mat& imageInverse(Mat &src);
	Mat& logTrans(Mat &src, bool blog10=false);
	Mat& expTrans(Mat &src, double basenum=1.1);
	Mat& gammaTrans(Mat &src, double gamma);
	Mat& piecewiseLinearTrans(Mat &src, vector<cv::Point> &linearFun);
	bool bitLayerTrans(Mat &src,vector<Mat>& bitmat, bool binary=false);
	Mat& bitLayerCombine(vector<Mat> &bitmat, int *bituse, bool binary=false);
private:
	Mat m_destMat;
};


实现

#include "processing.h"

//image inversion
Mat& section_3_2::imageInverse(Mat &src)
{
	m_destMat.create(src.rows, src.cols, CV_8UC3);
	int nChanel = src.channels();
	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			if(nChanel==1)
			{
				memset(dest_ptr+3*j, 255-src_ptr[j], 3);
			}
			else
			{
				int t = 3*j;
				dest_ptr[t] = 255-src_ptr[t];
				dest_ptr[t+1] = 255-src_ptr[t+1];
				dest_ptr[t+2] = 255-src_ptr[t+2];
			}
		}
	}
	return m_destMat;
}

//log transformation
Mat& section_3_2::logTrans(Mat &src, bool blog10)
{
	m_destMat.create(src.rows, src.cols, CV_8UC3);

	float k = blog10 ? 255/log10(256.f) : 255/log(256.f);
	uchar logtable[256]={0};
	for(int i=0; i<256; ++i)
	{
		logtable[i] = (blog10 ? saturate_cast<uchar>(log10(float(i+1))*k) : saturate_cast<uchar>(log(float(i+1))*k));
	}

	int nChanel = src.channels();
	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			if(nChanel==1)
			{
				memset(dest_ptr+3*j, logtable[src_ptr[j]], 3);
			}
			else
			{
				int t = 3*j;
				dest_ptr[t] = logtable[src_ptr[t]];
				dest_ptr[t+1] = logtable[src_ptr[t+1]];
				dest_ptr[t+2] = logtable[src_ptr[t+2]];
			}
		}
	}
	return m_destMat;
}

//exponent transformation
Mat& section_3_2::expTrans(Mat &src, double basenum)
{
	if(basenum <= 0)
		return m_destMat;

	m_destMat.create(src.rows, src.cols, CV_8UC3);

	double k = 255/(pow(basenum, 255)-1);
	uchar exptable[256]={0};
	for(int i=0; i<256; ++i)
	{
		exptable[i] = saturate_cast<uchar>((pow(basenum, i)-1)*k);
	}

	int nChanel = src.channels();
	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			if(nChanel==1)
			{
				memset(dest_ptr+3*j, exptable[src_ptr[j]], 3);
			}
			else
			{
				int t = 3*j;
				dest_ptr[t] = exptable[src_ptr[t]];
				dest_ptr[t+1] = exptable[src_ptr[t+1]];
				dest_ptr[t+2] = exptable[src_ptr[t+2]];
			}
		}
	}
	return m_destMat;
}

//gamma transformation
Mat& section_3_2::gammaTrans(Mat &src,double gamma)
{
	if(gamma<=0)
		return m_destMat;

	m_destMat.create(src.rows, src.cols, CV_8UC3);

	double k = 255/(pow(255.0, gamma)-1);
	uchar gammatable[256]={0};
	for(int i=0; i<256; ++i)
	{
		gammatable[i] = saturate_cast<uchar>((pow(double(i), gamma)-1)*k);
	}

	int nChanel = src.channels();
	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			if(nChanel==1)
			{
				memset(dest_ptr+3*j, gammatable[src_ptr[j]], 3);
			}
			else
			{
				int t = 3*j;
				dest_ptr[t] = gammatable[src_ptr[t]];
				dest_ptr[t+1] = gammatable[src_ptr[t+1]];
				dest_ptr[t+2] = gammatable[src_ptr[t+2]];
			}
		}
	}
	return m_destMat;
}

//piecewise linear transformation
Mat& section_3_2::piecewiseLinearTrans(Mat &src, vector<cv::Point> &linearFun)
{
	//at least two end points,first-0, last-255;
	if(linearFun.size()<2 || linearFun[0].x!=0 || linearFun[linearFun.size()-1].x!=255)
		return m_destMat;

	//check each point--every point's x coord should not less than the last one;
	for (size_t i=1; i<linearFun.size(); ++i)
	{
		if(linearFun[i].x<linearFun[i-1].x || linearFun[i-1].x>255 || linearFun[i].x>255 || 
			linearFun[i-1].y>255 || linearFun[i].y>255)
			return m_destMat;
	}

	m_destMat.create(src.rows, src.cols, CV_8UC3);
	
	//create the lookup table;
	uchar sectable[256]={0};
	int uplimit = min(256, linearFun[1].x);
	size_t j=0;
	for(int i=0;;)
	{
		float k = (linearFun[j+1].y-linearFun[j].y)/(float)(linearFun[j+1].x-linearFun[j].x);
		
		for(; i<=uplimit; ++i)
		{
			uchar pix = 0;
			//not vertical
			if(linearFun[j].x < linearFun[j+1].x)
			{
				pix = saturate_cast<uchar>(linearFun[j].y+k*(i-linearFun[j].x));
			}
			else
			{//vertical
				pix = linearFun[j].y;
			}
			sectable[i] = pix;
		}
		//shift the section and check
		if (++j < linearFun.size()-1)
		{
			uplimit = linearFun[j+1].x;
		}
		else
		{
			for (;i<256; ++i)
			{
				sectable[i] = 255;
			}
			break;
		}
	}
	//scan input image and set the output
	int nChanel = src.channels();
	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			if(nChanel==1)
			{
				memset(dest_ptr+3*j, sectable[src_ptr[j]], 3);
			}
			else
			{
				int t = 3*j;
				dest_ptr[t] = sectable[src_ptr[t]];
				dest_ptr[t+1] = sectable[src_ptr[t+1]];
				dest_ptr[t+2] = sectable[src_ptr[t+2]];
			}
		}
	}
	return m_destMat;
}

//bit layer transformation
bool section_3_2::bitLayerTrans(Mat &src,vector<Mat>& bitmat, bool binary)
{
	if(src.channels() != 1)
		return false;

	m_destMat = Mat::zeros(src.rows, src.cols, CV_8UC3);
	bitmat.clear();
	
	//create a 8 elements vector, 
	//note!- cv::Mat is ref-count,so don't just push_back it; copy to new Mat;
	for(int i=0; i<8; ++i)
	{
		Mat temp;
		m_destMat.copyTo(temp);
		bitmat.push_back(temp);
	}

	for (int i=0; i<src.rows; ++i)
	{
		uchar *src_ptr = src.ptr<uchar>(i);
		for (int j=0; j<src.cols; ++j)
		{
			uchar maskbyte = 0x01;
			for (int k=0; k<8; ++k)
			{		
				uchar *dest_ptr = bitmat[k].ptr<uchar>(i);
				uchar pixvalue = 0;
				if(binary)
					pixvalue = (src_ptr[j]&(maskbyte<<k))==0 ? 0 : 255;
				else
					pixvalue = src_ptr[j]&(maskbyte<<k);

				memset(dest_ptr+3*j, pixvalue, 3);
			}
		}
	}

	return true;
}

//combine specified bit image to a new one;
//param: bituse should be 8 elements arrays, if elem k is not 0,then use this bit;
//param: binary indicate whether the vector<Mat> is binary image;
Mat& section_3_2::bitLayerCombine(vector<Mat> &bitmat, int *bituse, bool binary)
{
	if(bitmat.size()!= 8)
		return m_destMat;

	m_destMat = Mat::zeros(bitmat[0].rows, bitmat[0].cols, CV_8UC3);

	for (int i=0; i<m_destMat.rows; ++i)
	{
		uchar *dest_ptr = m_destMat.ptr<uchar>(i);
		for (int j=0; j<m_destMat.cols; ++j)
		{
			uchar maskbyte = 0x01;
			uchar pixvalue = 0;
			int j3 = j*3;
			for (int k=0; k<8; ++k)
			{		
				if(!bituse[k])
					continue;
				uchar *src_ptr = bitmat[k].ptr<uchar>(i);
				if(binary)
					pixvalue |= (src_ptr[j3]&(maskbyte<<k));
				else
					pixvalue |= src_ptr[j3];
			}	

			memset(dest_ptr+j3, pixvalue, 3);
		}
	}

	return m_destMat;
}


下面给出几张处理的图像:

数字图像处理基本算法实现(1)--section3.2基本灰度变换_第1张图片数字图像处理基本算法实现(1)--section3.2基本灰度变换_第2张图片

分别是反转,gamma=0.5和log变换

数字图像处理基本算法实现(1)--section3.2基本灰度变换_第3张图片

分别是分段线性变换和指数变换后和指数变换前的图像

下面是比特分层的lena图像,左->右,上->下,分别为bit0--bit7的图像

数字图像处理基本算法实现(1)--section3.2基本灰度变换_第4张图片

下面是使用分层图像组合起来的图像

数字图像处理基本算法实现(1)--section3.2基本灰度变换_第5张图片数字图像处理基本算法实现(1)--section3.2基本灰度变换_第6张图片数字图像处理基本算法实现(1)--section3.2基本灰度变换_第7张图片

从左到右分别为使用bit6和bit7;bit5,bit6和bit7;bit3--bit7组合之后的图像,第三幅已经非常接近原始图像。

 

你可能感兴趣的:(算法,image,Blog,Arrays,float,图像处理)