1、
去噪
Mat denoising(Mat scr)
{
Mat dst;
medianBlur(scr, dst, 3); //中值滤波,3*3模板内排序并求中值取代原像素
//blur(scr, dst, Size(3, 3));//均值滤波,3*3模板内求取中间值取代原像素 ----------better than medianBlur
//GaussianBlur(scr, dst, Size(3, 3), 0, 0);//高斯滤波,
return dst;
}
2、
图像增强
//高通滤波
Mat HighPass(Mat scr)
{
Mat rst;
Mat kernel(3, 3, CV_32F, Scalar(-1));
// 分配像素置
kernel.at(1, 1) = 9;//8.9
filter2D(scr, rst, scr.depth(), kernel);
return rst;
}
//高反差保留——图像增强——高通滤波
// r = (pix[x,y]-avg(R))
//dst[x,y] = 128+|r|*r/(2*R)
Mat HighPass(IplImage *cut_img)
{
Mat src = cut_img;
int width=src.cols;
int heigh=src.rows;
Mat img;
src.copyTo(img);
Mat avg;
int R=5;
//GaussianBlur(img,avg,Size(R,R),0.0);
blur(img,avg,Size(R,R));
Mat dst(img.size(),CV_8UC3);
float tmp;
for (int y=0;y
{
uchar* imgP=img.ptr(y);
uchar* avgP=avg.ptr(y);
uchar* dstP=dst.ptr(y);
for (int x=0;x
{
float r0 = abs((float)imgP[3*x]-(float)avgP[3*x])/128;
tmp = abs( ((float)imgP[3*x])*r0 + 128*(1-r0));
tmp=tmp>255?255:tmp;
tmp=tmp<0?0:tmp;
dstP[3*x]=(uchar)(tmp);
float r1 = abs((float)imgP[3*x+1]-(float)avgP[3*x+1])/128;
tmp = (uchar)abs( ((float)imgP[3*x+1])*r1 + 128*(1-r1));
tmp=tmp>255?255:tmp;
tmp=tmp<0?0:tmp;
dstP[3*x+1]=(uchar)(tmp);
float r2 = abs((float)imgP[3*x+2]-(float)avgP[3*x+2])/128;
tmp = (uchar)abs( ((float)imgP[3*x+2])*r2 + 128*(1-r2));
tmp=tmp>255?255:tmp;
tmp=tmp<0?0:tmp;
dstP[3*x+2]=(uchar)(tmp);
}
}
return dst;
}
//Sobel算子
Mat SobelProcess(IplImage *cut_img)
{
Mat src=cut_img;
Mat src_gray;
Mat grad;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
// cvtColor(src, src_gray, COLOR_BGR2GRAY);
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X,Gradient Y
Sobel(src, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
Sobel(src, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
//![convert]
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
/// Total Gradient (approximate)
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
return grad;
}
3、
生成图像的梯度图
/*
求解梯度图,首先要注意数据的转换。因为本身读取的图像是8位的,其灰度值范围为0~255,而在求梯度的过程中,会出现梯度值大于255或者小于0的情况,因此在梯度图所存储的数据应该是以有符号整型的形式,即CV_32S。
另外,我采用的梯度求解方法为,当前像素的后一个像素减前一个像素的差值,作为当前像素的当前方向的梯度值。因为梯度本质上是求微分,因此对与图像,其存在两个方向上的梯度,即水平和垂直方向。这也是程序中求了两次灰度的原因。
在求了两个方向的梯度之后,再如何求出当前像素的梯度值,其方法也是很多的。我采用的是将水平和垂直梯度的绝对值相加,也可以采用平方和再开根号的方法,或者直接取二者最大值都行。
另外,解释一下,最后的那个类型转换函数,其作用是将当前数据类型的图像转换为unsigned char型,另外,在opencv中,其重载了很多算术运算符,比如这个函数里面的Ix+Iy就是代表对应位相加。
*/
void gradientGray(Mat &src, Mat &mag)----------src:灰度图;mag:生成的梯度图
{
const int H = src.rows, W = src.cols;
Mat Ix(H, W, CV_32S), Iy(H, W, CV_32S);
//因为计算出的梯度值可能有正有负,且值也可能会很大,故数据类型为整形
// 求水平方向梯度,处理左右边缘像素
for (int y = 0; y < H; y++){
Ix.at(y, 0) = abs(src.at(y, 1) - src.at(y, 0)) * 2;
for (int x = 1; x < W - 1; x++)
Ix.at(y, x) = abs(src.at(y, x + 1) - src.at(y, x - 1));
Ix.at(y, W - 1) = abs(src.at(y, W - 1) - src.at(y, W - 2)) * 2;
}
// 求垂直方向梯度,处理左右边缘像素
for (int x = 0; x < W; x++) {
Iy.at(0, x) = abs(src.at(1, x) - src.at(0, x)) * 2;
for (int y = 1; y < H - 1; y++)
Iy.at(y, x) = abs(src.at(y + 1, x) - src.at(y - 1, x));
Iy.at(H - 1, x) = abs(src.at(H - 1, x) - src.at(H - 2, x)) * 2;
}
/*for (int j = 0; j < H; j++)
for (int k = 0; k < W; k++)
{
mag.at(j, k) = min(Ix.at(j,k) + Iy.at(j, k), 255);
}*/
convertScaleAbs(min(Ix + Iy, 255), mag); //这句话和上面的for循环是同样的功能
}
4、
求图片直方图以及直方图曲线
//对梯度图像求直方图
void main()
{
string sampleImgPath = "E:\\ImgLibrary\\license_picture\\complete";
string exten1 = "*.png";
string exten2 = "*.jpg";
bool addPath1 = false;//true;
Directory dir;
vector filenames = dir.GetListFiles(sampleImgPath, exten1, addPath1);
vector filenames2 = dir.GetListFiles(sampleImgPath, exten2, addPath1);
vector::iterator it = filenames2.begin();
for (; it != filenames2.end(); ++it) {
filenames.push_back(*it);
}
int n = filenames.size();
int result = 0;
vector HistogramGood;
vector HistogramBad;
IplImage *graphGoodImg = cvCreateImage(cvSize(260, 1), 8, 3);
IplImage *graphBadImg = cvCreateImage(cvSize(260, 1), 8, 3);
IplImage *graphImg = cvCreateImage(cvSize(260, 1), 8, 3);
for (int i = 0; i < filenames.size(); i++)
{
string ImgPath = sampleImgPath + "\\" + filenames[i];
Mat Img = imread(ImgPath, 1);
//画曲线图
if (i == 0)
{
HistogramGood = curveHistogram(Img, filenames[i]);
vector::iterator Good_max = max_element(begin(HistogramGood), end(HistogramGood));
auto Good_min = min_element(begin(HistogramGood), end(HistogramGood));
graphGoodImg=drawFloatGraph(&HistogramGood[0], HistogramGood.size(), NULL, *Good_min, *Good_max, 400, 180, "GoodHist");
graphImg = drawFloatGraph(&HistogramGood[0], HistogramGood.size(), NULL, *Good_min, *Good_max, 400, 180, "curveHist");
}
else if (i < 20)
{
HistogramGood = curveHistogram(Img);
vector::iterator Good_max = max_element(begin(HistogramGood), end(HistogramGood));
auto Good_min = min_element(begin(HistogramGood), end(HistogramGood));
drawFloatGraph(&HistogramGood[0], HistogramGood.size(), graphGoodImg, *Good_min, *Good_max, 400, 180, "GoodHist");
drawFloatGraph(&HistogramGood[0], HistogramGood.size(), graphImg, *Good_min, *Good_max, 400, 180, "curveHist");
}
else if (i==20)
{
HistogramBad = curveHistogram(Img, filenames[i]);
vector::iterator Bad_max = max_element(begin(HistogramBad), end(HistogramBad));
auto Bad_min = min_element(begin(HistogramBad), end(HistogramBad));
graphBadImg=drawFloatGraph(&HistogramBad[0], HistogramBad.size(), NULL, *Bad_min, *Bad_max, 400, 180, "BadHist");
drawFloatGraph(&HistogramBad[0], HistogramBad.size(), graphImg, *Bad_min, *Bad_max, 400, 180, "curveHist");
}
else
{
HistogramBad = curveHistogram(Img, filenames[i]);
vector::iterator Bad_max = max_element(begin(HistogramBad), end(HistogramBad));
auto Bad_min = min_element(begin(HistogramBad), end(HistogramBad));
drawFloatGraph(&HistogramBad[0], HistogramBad.size(), graphBadImg, *Bad_min, *Bad_max, 400, 180, "BadHist");
drawFloatGraph(&HistogramBad[0], HistogramBad.size(), graphImg, *Bad_min, *Bad_max, 400, 180, "curveHist");
}
}
string GoodcurveHist = curveHistogram_savePath + "GoodcurveHist.jpg";
const char* GoodcurveHist_savePath = GoodcurveHist.data();
cvSaveImage(GoodcurveHist_savePath, graphGoodImg);
cvReleaseImage(&graphGoodImg);
string BadcurveHist = curveHistogram_savePath + "BadcurveHist.jpg";
const char* BadcurveHist_savePath = BadcurveHist.data();
cvSaveImage(BadcurveHist_savePath, graphBadImg);
cvReleaseImage(&graphBadImg);
string curveHist = curveHistogram_savePath + "curveHist.jpg";
const char* curveHist_savePath = curveHist.data();
cvSaveImage(curveHist_savePath, graphImg);
cvReleaseImage(&graphImg);
vector(filenames).swap(filenames);
vector(filenames2).swap(filenames2);
cout << "OK....";
}
vector
curveHistogram
(Mat gradimg)
{
int histSize = 256; //直方图针数
int hist_height = 256;
float range0[] = { 0, 255 }; //第0维数值变化范围
float * ranges[] = { range0 }; //第1维数值变化范围
//直方图统计
IplImage tmp_Img = gradimg;
IplImage* grad_Img = cvCloneImage(&tmp_Img);
CvHistogram * hist = cvCreateHist(1, &histSize, CV_HIST_ARRAY, ranges, 1);//创建一个直方图
cvCalcHist(&grad_Img, hist, 0, NULL);//计算一维直方图
//归一化直方图
cvNormalizeHist(hist, 1.0);
float maxValue, minValue; //直方图数值的max和min
int minIdx = 0, maxIdx = 0; //对应上述值时的下标号
cvGetMinMaxHistValue(hist, &minValue, &maxValue, &minIdx, &maxIdx);//得到最大最小值及其标号
//缩放最大值最小值以溶入图像
int scale = 2;
int avnum = 0;
//创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)
IplImage* hist_image = cvCreateImage(cvSize(histSize*scale, hist_height), 8, 3);
cvZero(hist_image);
vector Histogram;
//
绘制直方图
for (int j = 0; j
{
float bin_val = cvGetReal1D(hist->bins, j); //像素j的概率
int intensity = cvRound(bin_val*hist_height / maxValue); //要绘制的高度
cvRectangle(hist_image, cvPoint(j*scale, hist_height - 1), cvPoint((j + 1)*scale - 1, hist_height - intensity), CV_RGB(255, 0, 0));
Histogram.push_back(bin_val);
}
string hist_savePath = histImg_savePath + "\\" + filenames;
const char* histimg_savePath = hist_savePath.data();
cvSaveImage(histimg_savePath, hist_image);
//传直方图数组去画曲线
return Histogram;
}
5、切掉白边边
Mat cutImg(Mat img)
{
Mat cannyImg;
/* Canny(img, cannyImg, 10, 220, 3);//进行一次canny边缘检测
//string canny_savePath = cannyImg_save_path + "\\" + filenames;
//imwrite(canny_savePath, cannyImg);
//去除多余边边的过程:
int nRows = cannyImg.rows;
int nCols = cannyImg.cols;
int minx = 0, maxx = 0, miny = 0, maxy = 0;
for (int j = 0; j < nRows; j++)
{
int tmp = 0;
for (int i = 0; i < nCols; i++)
{
if (cannyImg.at(j, i) == 255)
{
tmp = 255;
break;
}
}
if (tmp != 0)
{
miny = j;
break;
}
}
for (int j = nRows - 1; j >= 0; j--)
{
int tmp = 0;
for (int i = 0; i < nCols; i++)
{
if (cannyImg.at(j, i) == 255)
{
tmp = 255;
break;
}
}
if (tmp)
{
maxy = j;
break;
}
}
for (int j = 0; j
{
int tmp = 0;
for (int i = 0; i
{
if (cannyImg.at(i, j) == 255)
{
tmp = 255;
break;
}
}
if (tmp)
{
minx = j;
break;
}
}
for (int j = nCols - 1; j >= 0; j--)
{
int tmp = 0;
for (int i = 0; i < nRows; i++)
{
if (cannyImg.at(i, j) == 255)
{
tmp = 255;
break;
}
}
if (tmp)
{
maxx = j;
break;
}
}
//裁剪图片 两个参数范围分别为左包含和右不包含
Mat roi_img;
roi_img = img(Range(miny, maxy), Range(minx, maxx));*/
return
roi_img ;
}