Opencv图像识别从零到精通(10)-----直方图均衡化与直方图拉伸

 一、直方图均衡化

直方图均衡化是灰度变换的一个重要应用,广泛应用在图像增强处理中,它是以累计分布函数变换为基础的直方图修正法,可以产生一幅灰度级分布具有均匀概率密度的图像,扩展了像素的取值动态范围。许多图像的灰度值是非均匀分布的,其中灰度值集中在一个小区间内的图像是很常见的,直方图均衡化是一种通过重新均匀地分布各灰度值来增强图像对比度的方法,经过直方图均衡化的图像对二值化阈值选取十分有利。一般来说,直方图修正能提高图像的主观质量,因此在处理艺术图像时非常有用。直方图均衡化处理的中心思想是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。

opencv中的调用就是下面这个函数,很方便

<span style="font-size:18px;">void equalizeHist(InputArray src,OutputArraydst );</span>

(1)通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。

(2)亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。

(3)对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。

(4)一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。

(5)一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。

单独使用直方图均衡化得到图像

<span style="font-size:18px;">#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, const char** argv )
{
     Mat img = imread("lena.jpg", CV_LOAD_IMAGE_COLOR); //open and read the image
     if (img.empty())
     {
          cout << "Image cannot be loaded..!!" << endl;
          return -1;
     }
     cvtColor(img, img, CV_BGR2GRAY); //change the color image to grayscale image
     Mat img_hist_equalized;
     equalizeHist(img, img_hist_equalized); //equalize the histogram
     //create windows
     namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
     namedWindow("Histogram Equalized", CV_WINDOW_AUTOSIZE);
     //show the image
     imshow("Original Image", img);
     imshow("Histogram Equalized", img_hist_equalized);
     waitKey(0); //wait for key press
     destroyAllWindows(); //destroy all open windows
     return 0;
}</span>

因为还是直方图均衡化,所以会用到直方图,如果单独使用直方图均衡化的话,就只有一个函数,所以这里可以处理图像后显示直方图和均衡化图像

<span style="font-size:18px;">#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include<opencv2\core\core.hpp>
using namespace cv;
using namespace std;
int img_Hist(Mat& image)
{
    if(!image.data)
    {
        cout << "fail to load image" << endl;
        return 0;
    }
    Mat img_gray;
    //GRAY
    if(image.channels()==3)
    {
    	cvtColor(image, img_gray, CV_BGR2GRAY);
    }
    else
    {
    	image.copyTo(img_gray);
    }
    cv::imwrite("img_gray.jpg",img_gray);

    MatND hist;
    int dims = 1;
    float hranges[] = {0, 255};
    const float *ranges[] = {hranges};   // 这里需要为const类型
    int size = 256;
    int channels = 0;
    // 计算图像的直方图
    calcHist(&img_gray, 1, &channels, Mat(), hist, dims, &size, ranges);    // cv 中是cvCalcHist
    int scale = 1;
    Mat imageShow(size * scale, size, CV_8U, Scalar(0));
    // 获取最大值和最小值
    double minVal = 0;
    double maxVal = 0;
    minMaxLoc(hist,&minVal, &maxVal, 0, 0);  //  cv中用的是cvGetMinMaxHistValue
    //显示直方图的图像
    int hpt = saturate_cast<int>(0.9 * size);

    for(int i = 0; i < 256; i++)
    {
        float value = hist.at<float>(i);           //   注意hist中是float类型    cv中用cvQueryHistValue_1D
        int realValue = saturate_cast<int>(value * hpt/maxVal);
        rectangle(imageShow,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
    }
    namedWindow("Hist");
    imshow("Hist", imageShow);
    cv::imwrite("hist.jpg",imageShow);
    Mat equalize_Hist;
    cv::equalizeHist(img_gray,equalize_Hist);

    namedWindow("equalize_Hist");
    imshow("equalize_Hist", equalize_Hist);
    cv::imwrite("equalize_Hist.jpg",equalize_Hist);
    // 计算图像的直方图
       calcHist(&equalize_Hist, 1, &channels, Mat(), hist, dims, &size, ranges);    // cv 中是cvCalcHist
       Mat imageShow_equal(size * scale, size, CV_8U, Scalar(0));
       // 获取最大值和最小值
       minMaxLoc(hist,&minVal, &maxVal, 0, 0);  //  cv中用的是cvGetMinMaxHistValue
       //显示直方图的图像
       hpt = saturate_cast<int>(0.9 * size);
       for(int i = 0; i < 256; i++)
       {
           float value = hist.at<float>(i);           //   注意hist中是float类型    cv中用cvQueryHistValue_1D
           int realValue = saturate_cast<int>(value * hpt/maxVal);
           rectangle(imageShow_equal,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
       }

       namedWindow("Hist_equalize");
       imshow("Hist_equalize", imageShow_equal);
       cv::imwrite("Hist_equalize.jpg",imageShow_equal);
    waitKey(0);
    return 0;
}
int main (int args, char** argv)
{
	Mat image = imread("lena.jpg", 1);    // 这里也可以是BGR 但是想想提取轮廓 效果是一样的
 	imshow("original", image);
 	img_Hist(image);
	waitKey();
    return 0;
}</span>

二、直方图拉伸

变换函数:将图像的一种灰度值经过变换得到另一个灰度。

直方图变换的核心就是变换函数,s=T(r),r是变换前的灰度值,s是变换后的灰度值,如要我们想将[a,b]区间的灰度变换到[0,255]范围内,则变换函数是:T(r)=255*(r-a)/(b-a)。

先要找到imin imax

<span style="font-size:18px;">int imax,imin;
for(imin=0;imin<256;imin++)
{
    if(hist.at<uchar>(imin)>minValue)
        break;
}
for(imax=255;imax>-1;imax--)
{
    if(hist.at<uchar>(imax)>minValue)
        break;
}  </span>

然后有一个映射函数

<span style="font-size:18px;">
Mat lookup(1,256,CV_8U);
for(int i=0;i<256;i++)
{
    if(lut.at<uchar>(i)<imin)
        lut.at<uchar>(i)=0;
    else if(lut.at<uchar>(i)>imax)
        lut.at<uchar>(i)=255;
    else
        lut.at<uchar>(i)=static_cast<uchar>(
        255.0*(i-imin)/(imax-imin)+0.5);
}  </span>

最后用LUT

<span style="font-size:18px;">LUT(image,lut,result);</span>

好文章分享http://blog.csdn.net/cv_ronny/article/details/17507671

时间: 2024-10-16 21:58:37

Opencv图像识别从零到精通(10)-----直方图均衡化与直方图拉伸的相关文章

Opencv图像识别从零到精通(8)-----灰度直方图

其实刚开始的时候,看很多的书和教程讲绘图和彩色图像等,但是我觉得还是先学会灰度直方图,因为灰度的dims是1,如果dims是3的就是彩色,同时知道前面将的彩色图像的像素访问,相信很快就可以迁移过去的.  一.换个角度认识图像(直方图) 第一个就是当我们面对图像的时候,我们面对的是抽象的矩阵,如下图,下面是0-255的灰度图像的表示,密密麻麻的 那么我们做的直方图,其实就是对这些像素值的统计,看下图,其中Bin是条数,数据和范围是对图的解释,一看就懂 二.准备知识 如果想绘制出来直方图,先要知道几

Opencv图像识别从零到精通(32)----直方图对比,模版匹配,方向投影

0.预备知识 归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内. 函数原型: <span style="font-size:18px;">void normalize(InputArray src,OutputArray dst, double alpha=1,doublebeta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() ) </span>

Opencv图像识别从零到精通(33)----moravec角点、harris角点

一.角点 图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints).特征点(feature points) 被大量用于解决物体识别,图像识别.图像匹配.视觉跟踪.三维重建等一系列的问题.我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析.如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就有使用价值. 图像特征类型可以被分为如下三种: <1>边缘                   

Opencv图像识别从零到精通(7)----图像平移、旋转、镜像

根据vc6.0c++的学习经验,如果可以很好的自己编程,让图像进行平移旋转这些操作,那么就好像能够清楚的看见图像的内部结构当然这里你怎么访问像素,这个可以自己选一种适合的,最多的是ptr指针,at也是挺多的.看着很简单的变换,可以对图像处理上手的更快,当然对于旋转可能就稍微i难了一点,不过opencv提供了resize(0,remap()等这样的函数,可以方便的让我们进行学习-特别是旋转的时候,有很多的变换,你可以任意旋转一个角度,也可能一直旋转,当然还可以保持图像大小不变的旋转和大小变换的旋转

Opencv图像识别从零到精通(26)---分水岭

分水岭是区域分割三个方法的最后一个,对于前景背景的分割有不错的效果. 分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭.分水岭的概念和形成可以通过模拟浸入过程来说明.在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭. 分水岭

Opencv图像识别从零到精通(28)----Kmeans

K-means算法算是个著名的聚类算法了,不仅容易实现,并且效果也不错,训练过程不需人工干预,实乃模式识别等领域的居家必备良品啊,今天就拿这个算法练练手.属于无监督学习中间接聚类方法中的动态聚类 流程: 1.随机选取样本中的K个点作为聚类中心 2.计算所有样本到各个聚类中心的距离,将每个样本规划在最近的聚类中 3.计算每个聚类中所有样本的中心,并将新的中心代替原来的中心 4.检查新老聚类中心的距离,如果距离超过规定的阈值,则重复2-4,直到小于阈值 聚类属于无监督学习,以往的回归.朴素贝叶斯.S

Opencv图像识别从零到精通(27)---grabcut

这是基于图论的分割方法,所以开始就先介绍了 Graph cuts,然后再到Grab cut   一. Graph cuts Graph cuts是一种十分有用和流行的能量优化算法,在计算机视觉领域普遍应用于前背景分割(Image segmentation).立体视觉(stereo vision).抠图(Image matting)等. 此类方法把图像分割问题与图的最小割(min cut)问题相关联.首先用一个无向图G=<V,E>表示要分割的图像,V和E分别是顶点(vertex)和边(edge)

Opencv图像识别从零到精通(34)---SIFI

   一.理论知识 Scale Invariant Feature Transform,尺度不变特征变换匹配算法,对于算法的理论介绍,可以参考这篇文章http://blog.csdn.net/qq_20823641/article/details/51692415,里面很详细,可以更好的学习.这里就不多介绍.后面就挑选重点的来说 二.SIFT 主要思想 SIFT算法是一种提取局部特征的算法,在尺度空间寻找极值点,提取位置,尺度,旋转不变量. 三.SIFT算法的主要特点: a) SIFT特征是图像

Opencv图像识别从零到精通(14)-----线性滤波和非线性滤波

一,噪声的介绍和卷积 二.各个滤波函数的解读,定义与源代码 三.综合所有的滤波,加滑动条控制核大小来blur 四.Matlab 辅助表达     一,噪声的介绍 图像噪声是图像在摄取或传输时所受的随机信号干扰,是图像中各种妨碍人们对其信息接受的因素.很多时候将图像噪声看成是多维随机过程,因而描述噪声的方法完全可以借用随机过程的描述,即用其概率分布函数和概率密度分布函数.我们常看到的就是淑艳噪声 salt&pepper,这里对噪声有理论的介绍http://blog.csdn.net/qq_2082