最全汇总:12种图像增强方法

  • 一、对比度与亮度增强
  • 二、直方图均衡化
    • 1.自定义的累计频率均衡法:
    • 2.opencv自带的equalizeHist()
    • 3.自适应的局部直方图均衡化
  • 三、指数变换增强
  • 四、gamma增强
    • 1.固定三次方增强:
    • 2.自定义系数增强:
  • 五、log转换增强
  • 六、laplaceEhance增强
  • 七、线性变换:
  • 八、分段线性拉伸算法:
  • 九、灰度级分层
  • 十、曝光过度对图像取反
  • 十一、高反差保留
  • 十二、Masaic算法(马赛克)
  • 十三、总结

一、对比度与亮度增强

使用场景:深色(黑色)背景的亮点(白点)检测

详情见:
对比度亮度图像增强及convertTo详解

实现:

void adjust(const cv::Mat &src, cv::Mat &dst, const float brightness, const float contrast)
{double B = brightness / 255.;double c = contrast / 255.;double k = tan((45 + 44 * c) / 180 * M_PI);double alpha = k;double beta = 127.5 * (1 + B) - k * 127.5 * (1 - B);src.convertTo(dst, -1, alpha, beta);
}

二、直方图均衡化

简单介绍一下,暂时用不到。

直方图均衡化是对一整幅图像进行映射,并不会对某些区域局部映射,对于那些部分区域偏暗或者偏亮的图像而言并不适用。同时直方图均衡化后的图像灰度级会减少,造成图像的一些细节消失。

对于一幅整体偏暗或者偏亮的图像而言比较适用。可以使得整幅图像的灰度值份均匀分布在整个动态范围[0,255]之内,从而增加图像的对比度。

1.自定义的累计频率均衡法:

步骤:
1.统计图像中每个灰度值像素的个数
2.计算每个灰度值像素的频率,并计算累计频率
3.将图像进行映射,图像的灰度值=图像原来灰度值*累计频率

单通道:

bool MyEqualizeHist(Mat gray, Mat & result)
{//统计0~255像素值的个数map<int, int>mp;for (int i = 0; i < gray.rows; i++){uchar* ptr = gray.data + i * gray.cols;for (int j = 0; j < gray.cols; j++){int value = ptr[j];mp[value]++;}}//统计0~255像素值的频率,并计算累计频率map<int, double> valuePro;int sum = gray.cols*gray.rows;double  sumPro = 0;for (int i = 0; i < 256; i++) {sumPro += 1.0*mp[i] / sum;valuePro[i] = sumPro;}//根据累计频率进行转换for (int i = 0; i < gray.rows; i++) {uchar* ptr1 = gray.data + i*gray.cols;for (int j = 0; j < gray.cols; j++) {int value = ptr1[j];double p = valuePro[value];result.at<uchar>(i, j) = p*value;}}return true;
}

多通道(RGB):

void MyEqualizeHistRgb(Mat& image)
{Mat imageRGB[3];split(image, imageRGB);for (int i = 0; i < 3; i++){MyEqualizeHist(imageRGB[i], imageRGB[i]);}merge(imageRGB, 3, image);imshow("result", image);
}

2.opencv自带的equalizeHist()

equalizeHist(Mat src, Mat dst);

步骤:

1.计算输入图像(8位)的直方图H;
2. 对直方图H进行归一化,使直方图bins的总和为255;
3.计算直方图的积分(integral of thehistogram); H′i=∑ 0≤j<i H(j)
4.使用H′作为查找表( look-uptable)对图像进行变换,具体像素值的变换公式为:dst(x,y)=H"(src(x,y))

该算法归一化亮度并增加图像的对比度。

结果与自定义的会不同。

3.自适应的局部直方图均衡化

局部直方图处理过程:

(1)设定某一大小的模板(矩形邻域),在图像中沿逐个像素移动;
(2)对每个像素位置,计算模板区域的直方图,对该局部区域进行直方图均衡或直方图匹配变换,变换结果只用于模板区域中心像素点的灰度值修正;
(3)模板(邻域)在图像中逐行逐列移动,遍历所有像素点,完成对整幅图像的局部直方图处理。

C++代码:

//C++
cvtColor(img,gray,COLOR_BGR2GRAY);
Ptr<CLAHE> clahe = createCLAHE();
clahe->apply(gray, dst);

python代码:

//python
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(4,4))  # 创建 CLAHE 对象
imgLocalEqu = clahe.apply(img)  # 自适应的局部直方图均衡化

clipLimit:颜色对比度的阈值,可选项,默认值 8
titleGridSize:局部直方图均衡化的模板(邻域)大小,可选项,默认值 (8,8)

三、指数变换增强

指数变换(Power-Law )的公式:S=c*R^r, 通过合理的选择c和r可以压缩灰度范围,算法以c=1.0/255.0, r=2实现。

以偏暗的图片测试,实际效果更暗。符合该公式推理,实际的像素值替换成了查找表的较小值。

自定义指数增强算法:

void Enhance::ExpEnhance(IplImage* img, IplImage* dst)
{// 由于oldPixel:[1,256],则可以先保存一个查找表uchar lut[256] ={0};double temp = 1.0/255.0;for ( int i =0; i<255; i++){lut[i] = (uchar)(temp*i*i+0.5);}for( int row =0; row <img->height; row++){uchar *data = (uchar*)img->imageData+ row* img->widthStep;uchar *dstData = (uchar*)dst->imageData+ row* dst->widthStep;for ( int col = 0; col<img->width; col++){for( int k=0; k<img->nChannels; k++){uchar t1 = data[col*img->nChannels+k];                dstData[col*img->nChannels+k] = lut[t1];}}        }
}//  OpenCV2.1版本之前使用IplImage*数据结构来表示图像,2.1之后的版本使用图像容器Mat来存储。
//  Mat dstImage = cvarrToMat(&dst1); // 将IplImage格式转换为Mat格式
//  IplImage dst1= (IplImage)(dst);// 将Mat类型的图片转换为IplImage // 以下为原创使用Mat的版本。void Enhance::ExpEnhance(Mat & img,double c, int r)
{if(img.channels() != 1){cvtColor(img,img,COLOR_BGR2GRAY);}uchar lut[256] ={0};for ( int i =0; i<255; i++){lut[i] = (uchar)( c * pow(i,r) +0.5);cout << c*i*i+0.5<<endl;}for(int i = 0;i < img.rows; i++){for(int j = 0;j < img.cols; j++){int pv = img.at<uchar>(i,j);img.at<uchar>(i,j) = lut[pv];}}
}

注:部分博客使用expf(n)计算e的n次方,个人认为是错的。expf(100)已经inf无穷大了。

srcmat.at<uchar>(i, j) = (unsigned char)(255.0 *(expf(srcmat.at<uchar>(i, j) - low_bound) / expf(up_bound - low_bound)));

四、gamma增强

特殊的指数增强,基于幂次变换的Gamma校正是图像处理中一种非常重要的非线性变换,它与对数变换相反,它是对输入图像的灰度值进行指数变换,进而校正亮度上的偏差。

通常Gamma校正长应用于拓展暗调的细节。通常来讲,当Gamma校正的值大于1时,图像的高光部分被压缩而暗调部分被扩展;当Gamma校正的值小于1时,相反的,图像的高光部分被扩展而暗调备份被压缩。

output = L^γ
当γ小于1时,低灰度区间拉伸,高灰度区间压缩;
当γ大于1时,低灰度区间压缩,高灰度区间拉伸。
当γ等于1时,简化成恒等变换。

1.固定三次方增强:

void Enhance::gammaEhance(Mat& image)
{Mat imageGamma(image.size(), CV_32FC3);for (int i = 0; i < image.rows; i++){for (int j = 0; j < image.cols; j++){imageGamma.at<Vec3f>(i, j)[0] = (image.at<Vec3b>(i, j)[0])*(image.at<Vec3b>(i, j)[0])*(image.at<Vec3b>(i, j)[0]);imageGamma.at<Vec3f>(i, j)[1] = (image.at<Vec3b>(i, j)[1])*(image.at<Vec3b>(i, j)[1])*(image.at<Vec3b>(i, j)[1]);imageGamma.at<Vec3f>(i, j)[2] = (image.at<Vec3b>(i, j)[2])*(image.at<Vec3b>(i, j)[2])*(image.at<Vec3b>(i, j)[2]);}}//归一化到0~255  normalize(imageGamma, imageGamma, 0, 255, CV_MINMAX);//转换成8bit图像显示  convertScaleAbs(imageGamma, imageGamma);imshow("gamma三次方增强", imageGamma);
}

2.自定义系数增强:

Mat Enhance::gammaWithParameter(Mat &img, float parameter)
{//建立查表文件LUTunsigned char LUT[256];for (int i = 0; i < 256; i++){//Gamma变换定义LUT[i] = saturate_cast<uchar>(pow((float)(i / 255.0), parameter)*255.0f);}Mat dstImage = img.clone();//输入图像为单通道时,直接进行Gamma变换if (img.channels() == 1){MatIterator_<uchar>iterator = dstImage.begin<uchar>();MatIterator_<uchar>iteratorEnd = dstImage.end<uchar>();for (; iterator != iteratorEnd; iterator++)*iterator = LUT[(*iterator)];}else{//输入通道为3通道时,需要对每个通道分别进行变换MatIterator_<Vec3b>iterator = dstImage.begin<Vec3b>();MatIterator_<Vec3b>iteratorEnd = dstImage.end<Vec3b>();//通过查表进行转换for (; iterator!=iteratorEnd; iterator++){(*iterator)[0] = LUT[((*iterator)[0])];(*iterator)[1] = LUT[((*iterator)[1])];(*iterator)[2] = LUT[((*iterator)[2])];}}return dstImage;
}

五、log转换增强

有效。测试透明物品模糊的边界增强后获得不错效果。

对数变换可以拓展低灰度值而压缩高灰度级值,让图像的灰度分布更加符合人眼的视觉特征。

经过适当的处理后,原始图像中低灰度区域的对比度将会增加,暗部细节将被增强。

对数变换公式为:

y = log(1+x)/b

其中,b是一个常数,用来控制曲线的弯曲程度,其中,b越小越靠近y轴,b越大越靠近x轴。表达式中的x是原始图像中的像素值,y是变换后的像素值。

实现:

void logEhance(Mat& image)
{Mat imageLog(image.size(), CV_32FC3);for (int i = 0; i < image.rows; i++){for (int j = 0; j < image.cols; j++){imageLog.at<Vec3f>(i, j)[0] = log(1 + image.at<Vec3b>(i, j)[0]);imageLog.at<Vec3f>(i, j)[1] = log(1 + image.at<Vec3b>(i, j)[1]);imageLog.at<Vec3f>(i, j)[2] = log(1 + image.at<Vec3b>(i, j)[2]);}}//归一化到0~255  normalize(imageLog, imageLog, 0, 255, CV_MINMAX);//转换成8bit图像显示  convertScaleAbs(imageLog, image);//imshow("Soure", image);imshow("Log", image);}

六、laplaceEhance增强

拥有锐化作用,对噪声比较敏感,需要先做平滑处理。

用来改善因扩散效应的模糊特别有效,因为它符合降制模型。扩散效应是成像过程中经常发生的现象。

Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;最后Laplacian算子不能检测边缘的方向.

实现:

void Enhance::laplaceEhance(Mat& image)
{Mat imageEnhance;Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, 0, 5, 0, 0, -1, 0);//多种卷积核可选。//Mat kernel = (Mat_<float>(3, 3) << 0, 1, 0, 1, -4, 1, 0, 1, 0);//Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);//Mat kernel = (Mat_<float>(3, 3) << 0, 1, 0, 1, 3, 1, 0, 1, 0);//Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);filter2D(image, imageEnhance, CV_8UC3, kernel);imshow("laplaceEhance", imageEnhance);
}

七、线性变换:

没什么好说的,就是直接做线性变换。

y = kx+b;

实现:

Mat Enhance::linearTransformation(Mat img, const float k, const float b)
{Mat dst = img.clone();for(int i=0; i<img.rows; i++){for(int j=0; j<img.cols; j++){for(int c=0; c<3; c++){float x =img.at<Vec3b>(i, j)[c];dst.at<Vec3b>(i, j)[c] = saturate_cast<uchar>(k* x + b);            }}}return dst;
}

八、分段线性拉伸算法:

图像灰度变换中常用的算法,在商业图像编辑软件Photoshop中也有相应的功能。分段线性拉伸主要是用于提高图像对比度,突显图像细节。

自定义增强,减弱的像素区间:

void Enhance::PiecewiseLinearTrans(cv::Mat& matInput, float x1, float x2, float y1, float y2)
{//计算直线参数//L1float K1 = y1 / x1;//L2float K2 = (y2 - y1) / (x2 - x1);float C2 = y1 - K2 * x1;//L3float K3 = (255.0f - y2) / (255.0f - x2);float C3 = 255.0f - K3 * 255.0f;//建立查询表uchar LUT[256] ={0};for (int m = 0; m < 256; m++){if (m < x1){LUT[m] = m * K1;}else if (m > x2){LUT[m] = m * K3 + C3;}else{LUT[m] = m * K2 + C2;}}//灰度映射for (int j = 0; j < matInput.rows; j++){for (int  i = 0; i < matInput.cols; i++){//查表gamma变换int x = matInput.at<uchar>(j,i);matInput.at<uchar>(j,i) = LUT[x];}}
}

九、灰度级分层

最简单的例子就是常用的opencv二值化算法:thresh、inRange都可以。

此处可以自行举一反三。

十、曝光过度对图像取反

字面意思:对值做255-x的操作即可。

实现:

void ExporeOver(IplImage* img, IplImage* dst)
{for( int row =0; row height; row++){uchar *data = (uchar*)img->imageData+ row* img->widthStep;uchar *dstData = (uchar*)dst->imageData+ row* dst->widthStep;for ( int col = 0; colwidth; col++){for( int k=0; knChannels; k++){uchar t1 = data[col*img->nChannels+k];uchar t2 = 255 - t1;dstData[col*img->nChannels+k] = min(t1,t2);}}      }
}

十一、高反差保留

高反差保留主要是将图像中颜色、明暗反差较大两部分的交界处保留下来,比如图像中有一个人和一块石头,那么石头的轮廓线和人的轮廓线以及面部、服装等有明显线条的地方会变被保留,儿其他大面积无明显明暗变化的地方则生成中灰色。

其表达形式为:

dst = r*(img – Blur(img))。

实现:

Mat HighPass(Mat img)
{Mat temp;GaussianBlur(img, temp,Size(7,7),1.6,1.6);int r=3;   Mat diff = img + r*(img-temp); //高反差保留算法return diff;
}

十二、Masaic算法(马赛克)

在日常中有时候保密或其他需要将图像马赛克,下面的算法实现图像马赛克功能(原理:用中心像素来表示邻域像素)。

uchar getPixel( IplImage* img, int row, int col, int k)
{return ((uchar*)img->imageData + row* img->widthStep)[col*img->nChannels +k];
}void setPixel( IplImage* img, int row, int col, int k, uchar val)
{((uchar*)img->imageData + row* img->widthStep)[col*img->nChannels +k] = val;
}// nSize:为尺寸大小,奇数
// 将邻域的值用中心像素的值替换
void Masic(IplImage* img, IplImage* dst, int nSize)
{int offset = (nSize-1)/2;for ( int row = offset; row <img->height - offset; row= row+offset){for( int col= offset; col<img->width - offset; col = col+offset){int val0 = getPixel(img, row, col, 0);int val1 = getPixel(img, row, col, 1);int val2 = getPixel(img, row, col, 2);for ( int m= -offset; m<offset; m++){for ( int n=-offset; n<offset; n++){setPixel(dst, row+m, col+n, 0, val0);setPixel(dst, row+m, col+n, 1, val1);setPixel(dst, row+m, col+n, 2, val2);}}}}
}

十三、总结

以上众多的方法在实战中有时不是单独使用的,滤波与各个方法相互的结合往往取得更好的效果。

图像处理秘籍:12种图像增强方法。【附代码】相关推荐

  1. java实现生日提醒_asp实现的可以提醒生日的几种方法附代码

    asp实现的可以提醒生日的几种方法附代码 更新时间:2008年06月20日 08:44:52   作者: asp提醒生日的原理一般就是把用户的出生日期和当前日期对比,如果少于几天则提醒显示,下面是几种 ...

  2. 12种降维方法终极指南(含Python代码)

    12种降维方法终极指南(含Python代码) 你遇到过特征超过1000个的数据集吗?超过5万个的呢?我遇到过.降维是一个非常具有挑战性的任务,尤其是当你不知道该从哪里开始的时候.拥有这么多变量既是一个 ...

  3. 图像处理注意力机制Attention汇总(附代码)

    原文链接: 图像处理注意力机制Attention汇总(附代码,SE.SK.ECA.CBAM.DA.CA等) 1. 介绍 注意力机制(Attention Mechanism)是机器学习中的一种数据处理方 ...

  4. php xml对象解析_php解析xml 的四种简单方法(附实例)

    XML处理是开发过程中经常遇到的,PHP对其也有很丰富的支持,本文只是对其中某几种解析技术做简要说明,包括:Xml parser, SimpleXML, XMLReader, DOMDocument. ...

  5. GAN如此简单的PyTorch实现,一张脸生成72种表情(附代码)

    [新智元导读]随着GAN的发展,单凭一张图像就能自动将面部表情生成动画已不是难事.但近期在Reddit和GitHub热议的新款GANimation,却将此技术提到新的高度.GANimation构建了一 ...

  6. 12种降维方法终极指南

    来源:Analytics Vidhya 编译:Bot 授权自 论智 你遇到过特征超过1000个的数据集吗?超过5万个的呢?我遇到过.降维是一个非常具有挑战性的任务,尤其是当你不知道该从哪里开始的时候. ...

  7. 收藏 | 机器学习领域必知必会的12种概率分布(附Python代码实现)

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:机器之心 AI博士笔记系列推荐 周志华<机器学习>手推笔记正式开源!可打印版本附pdf下载链接 机 ...

  8. 机器学习领域必知必会的12种概率分布(附Python代码实现)

    选自github 作者:graykode 编辑:机器之心 机器学习开发者需要了解的 12 种概率分布,这些你都了解吗? 机器学习有其独特的数学基础,我们用微积分来处理变化无限小的函数,并计算它们的变化 ...

  9. 2种图像增强方法:图像点运算和图像灰度化处理

    摘要:本文主要讲解图像点运算的灰度化处理,详细介绍常用的灰度化处理方法,并分享了图像颜色空间相互转换,以及三种灰度转换算法的实现. 本文分享自华为云社区<[Python从零到壹] 四十三.图像增 ...

最新文章

  1. 大写的服,看完这篇你还不懂RocketMQ算我输
  2. 实现AGI,强化学习就够了?Sutton、Silver师徒联手:奖励机制足够实现各种目标...
  3. 如何从PostgreSQL json中提取数组
  4. 虚线 实现_redis跳跃表实现
  5. PyCharm配置Docker
  6. gzp解压命令 linux_Linux下最常用的压缩及解压缩命令
  7. Python稳基修炼的经典案例1(计算机二级、初学者必须掌握的例题)
  8. POJ NOI0105-33 计算分数加减表达式的值
  9. python能做什么游戏-有趣又好玩的9个Python编程小游戏、简直太棒了
  10. 2.0显示为整数 java_Java如何将系统属性读取为整数?
  11. [转载] 【全面总结】Tensorflow 2.0+与Keras的联系与应用(含model详解)
  12. VB6(Fast Report Studio 4.6.80)
  13. matlab 同态滤波
  14. 龙格库塔算法原理详解
  15. 计算机启动方式如何选择USB启动,如何设置电脑从usb启动详细方法
  16. 关于PHP程序员技术职业生涯规划--swool大神韩天峰
  17. 库房计算机管理,库房管理
  18. python分析比赛_世界杯:用Python分析热门夺冠球队-(附源代码)
  19. git版本更迭的原理
  20. Mysql常用函数(一)

热门文章

  1. C++11关键字constexpr看这篇就够了
  2. 这就是传说中超难的N皇后?——详细图解!
  3. mac版photoshop滤镜库报错解法
  4. 电脑计算机怎么没有桌面显示器,电脑显示器没有图标怎么办
  5. seo外链怎么发才有效果?
  6. 2020.7.16 bug总结 第二周 (转载篇)
  7. 总是显示观战服务器请求失败,观战服务器数据请求失败
  8. SpreadJS:强大的数组公式(Array Function)
  9. 解决eclipse+tomcat开发时候修改配置文件自动重启服务器问题
  10. 阿里巴巴Java代码规范