图像增强是图像处理的第一步。这里集成了一些实际使用过程中有用的函数。
//读取灰度或彩色图片到灰度
Mat imread2gray(string path){
Mat src = imread(path);
Mat srcClone = src.clone();
if (CV_8UC3 == srcClone.type() )
cvtColor(srcClone,srcClone,CV_BGR2GRAY);
return srcClone;
}
算法核心在于判断读入图片的通道数,如果是灰度图片则保持;如果是彩色图片则转换为灰度图片。通过这样一个函数,就能够直接获得灰度图片。
//带有上下限的threshold
Mat threshold2(Mat src,int minvalue,int maxvalue){
Mat thresh1;
Mat thresh2;
Mat dst;
threshold(src,thresh1,minvalue,255, THRESH_BINARY);
threshold(src,thresh2,maxvalue,255,THRESH_BINARY_INV);
dst = thresh1 & thresh2;
return dst;
}
Opencv提供的threshold算法很强大,但是只能够取单门限。这里修改成可以取双门限的形式。
//自适应门限的canny算法
//canny2
Mat canny2(Mat src){
Mat imagetmp = src.clone();
double low_thresh = 0.0;
double high_thresh = 0.0;
AdaptiveFindThreshold(imagetmp,&low_thresh,&high_thresh);
Canny(imagetmp,imagetmp,low_thresh,high_thresh);
return imagetmp;}
void AdaptiveFindThreshold( Mat src,double *low,double *high,int aperture_size){
const int cn = src.channels();
Mat dx(src.rows,src.cols,CV_16SC(cn));
Mat dy(src.rows,src.cols,CV_16SC(cn));
Sobel(src,dx,CV_16S,1,0,aperture_size,1,0,BORDER_REPLICATE);
Sobel(src,dy,CV_16S,0,1,aperture_size,1,0,BORDER_REPLICATE);
CvMat _dx = dx;
CvMat _dy = dy;
_AdaptiveFindThreshold(&_dx, &_dy, low, high); }
void _AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high){
CvSize size;
IplImage *imge=0;
int i,j;
CvHistogram *hist;
int hist_size = 255;
float range_0[]={0,256};
float* ranges[] = { range_0 };
double PercentOfPixelsNotEdges = 0.7;
size = cvGetSize(dx);
imge = cvCreateImage(size, IPL_DEPTH_32F, 1);
// 计算边缘的强度, 并存于图像中
float maxv = 0;
for(i = 0; i < size.height; i++ ){
const short* _dx = (short*)(dx->data.ptr + dx->step*i);
const short* _dy = (short*)(dy->data.ptr + dy->step*i);
float* _image = (float *)(imge->imageData + imge->widthStep*i);
for(j = 0; j < size.width; j++){
_image[j] = (float)(abs(_dx[j]) + abs(_dy[j]));
maxv = maxv < _image[j] ? _image[j]: maxv;}}
if(maxv == 0){
*high = 0;
*low = 0;
cvReleaseImage( &imge );
return;}
// 计算直方图
range_0[1] = maxv;
hist_size = (int)(hist_size > maxv ? maxv:hist_size);
hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist( &imge, hist, 0, NULL );
int total = (int)(size.height * size.width * PercentOfPixelsNotEdges);
float sum=0;
int icount = hist->mat.dim[0].size;
float *h = (float*)cvPtr1D( hist->bins, 0 );
for(i = 0; i < icount; i++){
sum += h[i];
if( sum > total )
break; }
// 计算高低门限
*high = (i+1) * maxv / hist_size ;
*low = *high * 0.4;
cvReleaseImage( &imge );
cvReleaseHist(&hist); }
// end of canny2
我们在使用Opencv的canny算法的时候,一般是按照经验填写上下门限值。为了解决这个问题,通过自适应算法(算法来源我想不起来了),自动计算出上下门限。能够取得不错效果。