opencv初探(二)——直方图均衡化与双线性插值缩放
2016-01-03 18:25
537 查看
这两种算法均基于上一篇所提到的图像像素遍历,通过对每个像素进行相应操作,达到总体上的目的。
一、直方图均衡化
直方图均衡化是增强图像对比度的有效方法。通过对各像素频率的统计来重新分配该像素对应的新像素,但要保证像素之间的大小关系不能翻转,是以采取累积频率来分配像素。
二、双线性插值图片缩放
图片缩放有多种不同的算法,可根据目的相应的选择。双线性插值法比较简单而且效果也不错。该算法中根据缩放比例,从原图的像素中进行抽样组成新图像的像素。其中需要重点注意整数小数之间的转换以及像素之间对应的位置关系。
一、直方图均衡化
直方图均衡化是增强图像对比度的有效方法。通过对各像素频率的统计来重新分配该像素对应的新像素,但要保证像素之间的大小关系不能翻转,是以采取累积频率来分配像素。
void equalHist(Mat inputImage, Mat &outputImage) { int rowNumber = inputImage.rows; int colNumber = inputImage.cols; int total = rowNumber*colNumber; outputImage = Mat(rowNumber, colNumber, CV_8UC1); int freq[256] = { 0 };//各像素出现次数 for (int i = 0; i < rowNumber; i++) { uchar *pixel_adress = inputImage.ptr<uchar>(i); uchar *pixel_adress2 = outputImage.ptr<uchar>(i); for (int j = 0; j < colNumber; j++) { freq[int(pixel_adress[j])] += 1;//对应次数+1 //cout << "pixel: " << int(pixel_adress[j]) << endl; } } double freq2[256] = { 0 };//各像素出现频率累积,从0到255 freq2[0] = double(freq[0]) / total; //cout <<"freq[255]:"<<freq[255]<< " freq[0]:" << freq[0] << " freq2[0]:" << freq2[0] << endl; for (int j = 1; j < 256; j++) { freq2[j] = freq2[j - 1] + double(freq[j]) / total; } //cout <<"freq2[255]:"<<freq2[255]<< " freq2[0]:" << freq2[0] << " freq2[0]:" << freq2[0] << endl; uchar pixel[256] = { 0 };//各像素根据累积频率对应的新像素 for (int k = 0; k < 256; k++) { pixel[k] = uchar(freq2[k] * 256); } for (int i = 0; i < rowNumber; i++) { uchar *in_pixel = inputImage.ptr<uchar>(i); uchar *out_pixel = outputImage.ptr<uchar>(i); for (int j = 0; j < colNumber; j++) { out_pixel[j] = pixel[int(in_pixel[j])]; } } imshow("out_pixel", outputImage); imwrite("out_pixel.jpg", outputImage); }
二、双线性插值图片缩放
图片缩放有多种不同的算法,可根据目的相应的选择。双线性插值法比较简单而且效果也不错。该算法中根据缩放比例,从原图的像素中进行抽样组成新图像的像素。其中需要重点注意整数小数之间的转换以及像素之间对应的位置关系。
void myResize( Mat inputImage, Mat &outputImage, const double onRows ,const double onCols) {//双线性插值法缩放图片 int rowNum = int(inputImage.rows*onRows); int colNum = int(inputImage.cols*onCols); outputImage = Mat(rowNum, colNum,inputImage.type()); for (int i = 0; i < rowNum; i++) { double cof[6] = { 0 }; double sampleRow = (double(i))/onRows; uchar *pixel_adress2 = outputImage.ptr<uchar>(i);//目的像素行首地址 for (int j = 0; j < colNum; j++) { double sampleCol = (double(j)) / onCols; uchar *pixel_adress = inputImage.ptr<uchar>(int(sampleRow));//源像素行首地址 uchar *pixel_adress3; if ((int(sampleRow) + 1) == rowNum) { pixel_adress3 = inputImage.ptr<uchar>(int(sampleRow) - 1); } else pixel_adress3 = inputImage.ptr<uchar>(int(sampleRow) + 1);//下一行源像素行首地址 //cout << int(sampleRow) + 1 << " rowNum: " << rowNum << endl; cof[4] = sampleRow - (int)sampleRow;//t cof[5] = sampleCol - (int)sampleCol;//u cof[0] = (1 - cof[4])*(1 - cof[5]);//(1-t)*(1-u) cof[1] = cof[4] * (1 - cof[5]);//t*(1-u) cof[2] = (1 - cof[4])*cof[5];//(1-t)*u cof[3] = cof[4] * cof[5];//t*u for (int k = 0; k<outputImage.channels(); k++)//对每个像素进行操作 { pixel_adress2[j*3+k] = cof[0] * pixel_adress[int(sampleCol)*3+k] + cof[1] * pixel_adress[int(sampleCol)*3 + k] + cof[2] * pixel_adress3[int(sampleCol)*3+k] + cof[3] * pixel_adress3[int(sampleCol)*3 + k]; //pixel_adress2[j] = uchar(cof[0] * inputImage.at<uchar>((int)sampleRow, (int)sampleCol)) + cof[1] * inputImage.at<uchar>((int)sampleRow, (int)sampleCol + 1) //+ cof[2] * inputImage.at<uchar>((int)sampleRow + 1, (int)sampleCol ) + cof[3] * inputImage.at<uchar>((int)sampleRow + 1, (int)sampleCol + 1); pixel_adress2[j] > 256 ? 256 : pixel_adress2[j];//防止像素大小超出范围 pixel_adress2[j] < 0 ? 0 : pixel_adress2[j]; } } } imwrite("output.jpg", outputImage); imshow("output", outputImage); }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析