虽然学的是与图像处理有关的专业,也看过一些图像处理的书,基本的算法原理也懂,但是一直以来都是用现成的库,没有自己按照算法编过,或者有些算法照着别人的代码敲一遍,什么也没学到,所以一直就想好好补补,试着自己去按照算法描述编一下,不管效率,允许小的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;
}
下面给出几张处理的图像:
分别是反转,gamma=0.5和log变换
分别是分段线性变换和指数变换后和指数变换前的图像
下面是比特分层的lena图像,左->右,上->下,分别为bit0--bit7的图像
下面是使用分层图像组合起来的图像
从左到右分别为使用bit6和bit7;bit5,bit6和bit7;bit3--bit7组合之后的图像,第三幅已经非常接近原始图像。