常见的8种图像增强算法及其opencv实现

1.直方图均衡化

直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。 
  这种方法通常用来增加许多图像的局部对比度。这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作。

参考来源 openCV直方图均衡化https://blog.csdn.net/zhangfuliang123/article/details/74170894

首先openCV没有直方图直接显示的函数,所以我们需要创建直方图来自定义绘图,函数如下:

/*
     width:直方图宽度     height:直方图高度     scale:
*/
IplImage* showImageHistogram(IplImage** image, int width, int height ,int scale){
 
    int dims = 1;
    int histSize = 256;
    float frange[] = { 0, 255 };
    float* ranges[] = { frange };
    //创建一个直方图     CV_HIST_ARRAY多维密集数组
    CvHistogram*  hist = cvCreateHist(dims, &histSize, CV_HIST_ARRAY, ranges);
    //根据输入图像计算直方图
    cvCalcHist(image, hist);
 
 
    //绘制直方图区域
    IplImage* histImage = cvCreateImage(cvSize(width*scale, height), IPL_DEPTH_8U, 1);
    //直方图背景区域置位白色
    cvRectangle(histImage, cvPoint(0, 0), cvPoint(histImage->width, histImage->height), CV_RGB(255,255,255), CV_FILLED);
    //获取最大值
    float maxHistValue = 0;
    cvGetMinMaxHistValue(hist, NULL, &maxHistValue, NULL,NULL);
    //绘制各个灰度级的直方图
    for (int i = 0; i < width; i++){
        float value = cvQueryHistValue_1D(hist, i);
        int drawHeight = cvRound((value / maxHistValue) * height);
        cvRectangle(histImage, cvPoint(i*scale, height-1), cvPoint((i+1)*scale -1, height-drawHeight), cvScalar(i, 0, 0, 0), CV_FILLED);
    }
    return histImage;
 
}

直接处理灰度图:

  • 使用OpenCV函数 EqualizeHist 对直方图均衡化

void histGrayChange(){
    const char* picName = "test.tif";//test.tif lenaRGB.tif
    //采用IplImage *img = cvLoadImage(picName)默认值是CV_LOAD_IMAGE_COLOR  读取无论原始图像的通道数是多少,都将被转换为3个通道读入。
    //IplImage *img = cvLoadImage(picName);
 
    //******以灰度图像读入,强制转换为单通道*****
    IplImage *img = cvLoadImage(picName,CV_LOAD_IMAGE_GRAYSCALE);
    if (img == NULL){
        cout << "Load File Failed." << endl;
    }
    cout << "ChannelL:" << img->nChannels;
 
 
    IplImage* imgDst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
    //直方图均衡化
    cvEqualizeHist(img, imgDst);
    
    cvNamedWindow("Origin", CV_WINDOW_AUTOSIZE);
    cvShowImage("Origin", img);
 
    cvNamedWindow("Result", CV_WINDOW_AUTOSIZE);
    cvShowImage("Result", imgDst);
 
    //
    int histImageWidth = 255;
    int histImageHeight = 150;
    int histImageScale = 2;
    IplImage *histImage1 = showImageHistogram(&img, histImageWidth, histImageHeight, histImageScale);
    cvNamedWindow("Hist1", CV_WINDOW_AUTOSIZE);
    cvShowImage("Hist1", histImage1);
 
    IplImage *histImage2 = showImageHistogram(&imgDst, histImageWidth, histImageHeight, histImageScale);
    cvNamedWindow("Hist2", CV_WINDOW_AUTOSIZE);
    cvShowImage("Hist2", histImage2);
 
 
    cvWaitKey();
 
    cvDestroyWindow("Origin"); cvReleaseImage(&img);
    cvDestroyWindow("Result"); cvReleaseImage(&imgDst);
 
}

也可以实现对彩色图片的直方图均衡化,代码就在前面的链接里,不贴了。

2、对数图像增强算法

对数图像增强是图像增强的一种常见方法,其公式为: S = c log(r+1),其中c是常数(以下算法c=255/(log(256)),这样可以实现整个画面的亮度增大。

void LogEnhance(IplImage* img, IplImage* dst)
{
    // 由于oldPixel:[1,256],则可以先保存一个查找表
    uchar lut[256] ={0};
 
    double temp = 255/log(256);
 
    for ( int i =0; i<255; i++)
    {
        lut[i] = (uchar)(temp* log(i+1)+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];
            }
        }        
    }    
}

3、指数图像增强算法

指数图像增强的表达为:S = cR^r,通过合理的选择c和r可以压缩灰度范围,算法以c=1.0/255.0, r=2实现。

void 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];
            }
        }        
    }    
}

4、加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);
                }
            }
        }
    }
}

5、曝光过度问题处理

对于曝光过度问题,可以通过计算当前图像的反相(255-image),然后取当前图像和反相图像的较小者为当前像素位置的值。

// 过度曝光原理:图像翻转,然后求原图与反图的最小值
void ExporeOver(IplImage* img, IplImage* dst)
{
    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];
                uchar t2 = 255 - t1;
                dstData[col*img->nChannels+k] = min(t1,t2);
            }
        }        
    }
}

6、高反差保留

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

测试代码:

int main(int argc, char* argv[])
{const char* Path = "02.bmp";IplImage *img = cvLoadImage(Path,CV_LOAD_IMAGE_ANYCOLOR);IplImage *dst = cvCreateImage(cvGetSize(img), img->depth, img->nChannels);cout<<"输入你要选择的操作:"<<endl;cout<<"1、曝光过度"<<endl;cout<<"2、加马赛克"<<endl;cout<<"3、对数增强"<<endl;cout<<"4、指数增强"<<endl;cout<<"请输入你的选择:";int choice = 1;cin>>choice;switch (choice){case 1: ExporeOver(img, dst);   //这四个算法中总觉得某个算法有问题break;case 2: Masic(img, dst, 21);break;case 3: LogEnhance(img, dst);break;case 4:ExpEnhance(img, dst);break;default:cout<<"输入错误"<<endl;break;              }cvSaveImage("dst.jpg",dst);cvNamedWindow("SRC",1);cvNamedWindow("DST", 1);cvShowImage("SRC", img);cvShowImage("DST", dst);cvWaitKey();return 0;
}

7.拉普拉斯算子图像增强

使用中心为5的8邻域拉普拉斯算子与图像卷积可以达到锐化增强图像的目的。

拉普拉斯算子增强局部的图像对比度的opencv代码:

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
 
using namespace cv;
 
int main(int argc, char *argv[])
{
    Mat image = imread("/Users/shandiangou/Downloads/lena.png");
    if (image.empty())
    {
        std::cout << "打开图片失败,请检查" << std::endl;
        return -1;
    }
    imshow("原图像", image);
    waitKey();
    Mat imageEnhance;
    Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, 0, 5, 0, 0, -1, 0);
    filter2D(image, imageEnhance, CV_8UC3, kernel);
    imshow("拉普拉斯算子图像增强效果", imageEnhance);
    waitKey();
    return 0;
}

参考博客:直方图均衡化、拉普拉斯算子图像增强、Gamma校正https://blog.csdn.net/sinat_28296297/article/details/77972023

OpenCV_基于Laplacian算子的图像边缘增强https://blog.csdn.net/icvpr/article/details/8502949

8.Gamma校正

伽马变换主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度。伽马变换对图像的修正作用其实就是通过增强低灰度或高灰度的细节实现的。

实现代码

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
 
#include <iostream>
 
using namespace cv;
using namespace std;
 
// Normalizes a given image into a value range between 0 and 255.
Mat norm_0_255(const Mat& src) {
    // Create and return normalized image:
    Mat dst;
    switch(src.channels()) {
        case 1:
            cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
            break;
        case 3:
            cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
            break;
        default:
            src.copyTo(dst);
            break;
    }
    return dst;
}
 
int main(int argc, const char *argv[]) {
    // Get filename to the source image:
    // Load image & get skin proportions:
    Mat image = imread("/Users/shandiangou/Downloads/guobao.jpeg");
    // Convert to floating point:
    Mat X;
    image.convertTo(X, CV_32FC1);
    //image.convertTo(X, CV_32F);
    // Start preprocessing:
    Mat I;
    float gamma = 3;
    pow(X, gamma, I);
    
    
    // Draw it on screen:
    imshow("Original Image", image);
    waitKey();
    imshow("Gamma correction image", norm_0_255(I));
    // Show the images:
    waitKey();
    // Success!
    return 0;  
}

暂时总结的就这8类,其他的之后再添

Opencv 学习---8种常用图像增强算法相关推荐

  1. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

  2. [转载] java实现四种常用排序算法

    参考链接: 用Java排序 四种常用排序算法 ##注:从小到大排 ##冒泡排序## 特点:效率低,实现简单 思想:每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有 ...

  3. 几种常用回归算法——线性回归、支持向量机回归和KNN回归

    欢迎关注,敬请点赞! 台湾何时归--几种常用回归算法 线性回归LR(Linear Regression) 代码展示(加噪声的正旋函数,狭义线性回归) 支持向量机回归SVR(Support Vector ...

  4. 常用图像增强算法实现——直方图均衡

    1.前言 对于原始对比度较低的图像,我们可以提高对比度来增强图像的辨识度,改善图像的视觉效果,转换为更适合人或者机器处理的形式,去除无用的信息,提高使用价值.典型的比如CT图像增强,去雾去雨,静脉增强 ...

  5. 视觉直观感受7种常用排序算法

    视觉直观感受若干常用排序算法 1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状 ...

  6. 8种常用排序算法稳定性分析

    选择排序.快速排序.希尔排序.堆排序不是稳定的排序算法 冒泡排序.插入排序.归并排序和基数排序都是稳定的排序算法. [1]为什么要区分排序算法的稳定性? 排序算法的稳定性通俗地讲就是能保证排序前两个相 ...

  7. 五种常用排序算法总结

    本篇文章讲的是以下五种常用的排序算法: 一.冒泡排序 1.原理 每次从前往后遍历整个数组,每一项与其后一项进行对比,若符合要求(从大到小或从小到大),就交换位置. 一遍循环结束后,最大(小)的值就会被 ...

  8. 我总结了五种常用聚类分析算法,推荐收藏

    大量数据中具有"相似"特征的数据点或样本划分为一个类别.聚类分析提供了样本集在非监督模式下的类别划分. 基本思想 物以类聚.人以群分 常用于数据探索或挖掘前期 没有先验经验做探索性 ...

  9. 理论+股市数据实战,总结了五种常用聚类分析算法

    来源:数据STUDIO 大量数据中具有"相似"特征的数据点或样本划分为一个类别.聚类分析提供了样本集在非监督模式下的类别划分. 基本思想 物以类聚.人以群分 常用于数据探索或挖掘前 ...

最新文章

  1. HashFlare矿池退出BTC挖矿,Coingeek矿池继续增加BCH算力
  2. C语言主应用程序在哪设置,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...
  3. 两种思路将Python中两个有序数组合并为一个有序数组
  4. Scala多线程:使用Executors提交Callable任务代码示例
  5. [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)
  6. [转]Java书籍Top 10
  7. 修改intellij(idea)中mybatis对应的xml背景颜色
  8. AI正在打王者荣耀排位赛,背后是腾讯100亿开放新战略
  9. Oracle 12C R2-新特性-SQLPLUS提供查看历史命令的功能
  10. STL笔记 ( 迭代器 )
  11. Office2016专业版打开超链接时提示“您的组织策略阻止我们为您完成此操作。...”问题解决
  12. 改变elementui的switch宽度、高度
  13. 【QUARTUSII】数字电路设计仿真实验
  14. Cousera - Deep Learning - 课程笔记 - Week 15
  15. 《道德经》和《圣经》中的“道”
  16. python中content什么意思_python中requests的response.text与response.content区别
  17. Mathematica最简教程
  18. Vue美食杰项目个人主页
  19. 存地失人,人地皆失;存人失地,人地皆存。
  20. 完美解决微信页面返回不刷新问题

热门文章

  1. 什么时候适合养生?蜜拓蜜:现在就是最好的时间
  2. 51单片机二进制转bcd码c语言,16位二进制数转换成BCD码的的快速算法-51单片机...
  3. 《电力系统自动化》课程教学大纲
  4. .NET实现ms-Word中字数统计
  5. 关于微信公号自定义菜单链接,跳转到历史消息界面URL
  6. win 10 + vs2017+C++的运行环境练习的2048游戏(附源码)
  7. PHP实现简单部分功能的博客系统
  8. 166 docker 如何删除image
  9. GoPower运动功率计
  10. 清华计算机考研 年龄,清华大学2020研究生录取数据公布,最小博士仅有18岁