虽然学的是与图像处理有关的专业,也看过一些图像处理的书,基本的算法原理也懂,但是一直以来都是用现成的库,没有自己按照算法编过,或者有些算法照着别人的代码敲一遍,什么也没学到,所以一直就想好好补补,试着自己去按照算法描述编一下,不管效率,允许小的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组合之后的图像,第三幅已经非常接近原始图像。