• 图像对比度增强算法

    2017-04-24 09:11:45
    论述了几种基于灰度直方图的图像对比度增强算法。

    一、全局对比度增强1

    1. 直方图均衡化 Histogram Equalization

    a. 基本思想

    对于图像中的灰度点做映射,使得整体图像的灰度大致符合均匀分布。增强图像的对比度。
    - 对于灰度值连续的情况,使用灰度的累积分布函数CDF做转换函数,可以使得输出图像的灰度符合均匀分布。
    - 对于灰度值不连续的情况,存在舍入误差,得到的灰度分布大致符合均匀分布。
    - 直观地理解,如果某一个灰度范围(如200-201)的像素点很少,那么它的概率密度值就会很小,所以CDF在200-201附近的增长变化就会很小;反之,如果某一个灰度范围(如100-101)的像素点很多,CDF在100-101附近的增长变化会很大。总体来看,以灰度为横轴,CDF为纵轴画曲线。这种向上凸的曲线,很像gamma变换: s=crγγ<1的情形。将灰度集中的部分拉伸,而将灰度不集中的部分压缩,达到提高对比度的效果。
    - 直方图均衡可以看做自适应的gamma变换或者分段变换。前者的优势在于,不需要指定任何参数,所有运算都是基于图像本身的。

    b. 算法
    1. 根据图像灰度计算灰度概率密度函数PDF
    2. 计算累积概率分布函数CDF
    3. CDF归一化到原图灰度取值范围,如[0,255]。
    4. 之后CDF四舍五入取整,得到灰度转换函数sk=T(rk)
    5. CDF作为转换函数,将灰度为rk的点转换为sk灰度
    c. matlab实验

    代码2

    %% 直方图均衡
    clear all;clc;close all;
    ImgFile='E:\图像处理\冈萨雷斯图片库\DIP3E_Original_Images_CH03\Fig0310(b)(washed_out_pollen_image).tif';
    ImgIn=imread(ImgFile);
    ImgHistEq=histeq(ImgIn,256);
    figure;subplot(121);imshow(uint8(ImgIn));title('原图');
    subplot(122);imshow(ImgHistEq);title('全局灰度增强 - 直方图均衡');
    figure;subplot(121);imhist(ImgIn,256);
    axis([0 255 0 1e5]);title('原图的直方图');
    subplot(122);imhist(ImgHistEq,256);axis([0 255 0 1e5]);title('直方图均衡化后的直方图');
    % 自定义直方图均衡
    [counts,x]=imhist(ImgIn,256);
    cum_counts=cumsum(counts);
    cum_counts=uint8(cum_counts/max(cum_counts)*255);% 转化函数
    figure;plot(x,cum_counts);axis([0 255 0 255]);
    xlabel('原图灰度');ylabel('转换后灰度');title('原图CDF转化的灰度映射函数');
    ImgOut=nan(size(ImgIn));
    for i=1:length(x)
        ImgOut(ImgIn==x(i))=cum_counts(i);
    end
    ImgOut=uint8(ImgOut);
    figure;imshow(uint8(ImgOut));title('自定义直方图均衡')
    figure;imhist(ImgOut,256);axis([0 255 0 1e5]);title('自定义直方图均衡的直方图')

    输出:
    原图和均衡化后的图
    图1. 原图和均衡化后的图。均衡后图像对比度明显增强,纹理和边缘更加清晰。

    原图和均衡化后的图的直方图
    图2. 原图和均衡化后的图的直方图。原图灰度分布在很狭窄的区间约[90,140]内。均衡化后灰度较为均匀的分布在整个[0, 255]区间内。

    cdf
    图3. 原图CDF归一化到[0, 255]后作为灰度变换函数。为了方便显示,画成连续曲线。

    自定义均衡的直方图
    图4. 自定义均衡的直方图。和Matlab自带histeq输出基本一致。

    2. 直方图匹配 Histogram Matching

    a. 基本思想

    我的理解:

    对于图像中的灰度点做映射,使得整体图像的灰度大致符合给定的分布。
    想要图像的直方图Hs和期望直方图Hd相同, 那么二者的CDF也是相同的.
    也就是说, 对于某一个灰度x, CDFs(x)=CDFd(x). 所以, 如果CDFs(x)=CDFd(y). 那么我们令x=y.
    也就是将原图的x灰度映射为y灰度. 相当于将图像直方图的横轴做了一个点对点的缩放操作.
    这个缩放操作的结果就是图像直方图向理想直方图靠近.
    在缩放过程中, 如果图像的直方图某一段灰度区间被拉长了, 因为灰度都是整数, 所以直方图的bin会变得稀疏.
    所以,
    最终的直方图匹配的结果就是直方图的bin变得稀疏了. 有的灰度区间没有灰度点.

    • 对于某些图像,灰度分布过于不均衡,例如背景很大且均匀。直接做直方图均衡会把前景“洗白”,效果很差。
    • 直方图匹配需要设定一个直方图分布。不同的图像,此分布可能不同。
    b. 算法
    1. 根据图像计算概率密度分布pr(r)
    2. 根据pr(r)计算累计分布函数sk=T(rk)
    3. 根据给定的目标分布pz(z)计算累计分布函数G(zq)
    4. 对于每一个k,找到一个q,使得G(zq)约等于sk
    5. 将原图中灰度为k的点变为灰度q
    c. Matlab实验
    clear all;clc;close all;
    ImgFile='E:\图像处理\冈萨雷斯图片库\DIP3E_Original_Images_CH03\Fig0323(a)(mars_moon_phobos).tif';
    ImgIn=imread(ImgFile);
    figure;subplot(121);imshow(ImgIn);title('原图')
    subplot(122);imhist(ImgIn);title('原图Hist')
    % histeq
    ImgHistEq=histeq(ImgIn);
    figure;subplot(121);imshow(ImgHistEq);title('Hist EQ');
    subplot(122);imhist(ImgHistEq,256);title('Hist EQ')
    % 根据3.35(a)估计的分布
    x=[0 8 16 180 200 255];
    Y=[0 70000 8000 0 3139 0];
    xi=0:255;
    yi = interp1q(x',Y',xi');
    figure;plot(xi,yi,'.');title('目标 Hist')
    ImgHistMatch = histeq(ImgIn, yi);
    figure;subplot(121);imshow(ImgHistMatch);title('histeq匹配')
    subplot(122);imhist(ImgHistMatch,256);title('histeq匹配直方图')

    输出:
    这里写图片描述
    图5. 原图和直方图

    这里写图片描述
    图6. 直方图均衡后图像及直方图

    这里写图片描述
    图7. 目标直方图

    这里写图片描述
    图8. 直方图匹配图像和直方图

    自定义直方图匹配

    %% 自定义匹配
    clear all;clc;close all;
    ImgFile='E:\图像处理\冈萨雷斯图片库\DIP3E_Original_Images_CH03\Fig0323(a)(mars_moon_phobos).tif';
    ImgIn=imread(ImgFile);
    x=[0 8 16 180 200 255];
    Y=[0 70000 8000 0 3139 0];
    xi=0:255;
    yi = interp1q(x',Y',xi');
    [counts, x]=imhist(ImgIn,256);
    cum_counts=cumsum(counts);% 累加CDF
    % 归一化到[0 255]
    cum_counts=cum_counts./numel(ImgIn);
    s_k=round(cum_counts*255);
    cum_yi=cumsum(yi);% 目标累加CDF
    g_z=round(cum_yi./sum(yi)*255); 
    figure;plot(s_k,'r');hold on;plot(g_z,'g');grid on;hold off;
    legend('s_k','g_z')
    axis([0 255 0 255]);title('原图累计CDF 和 目标累计CDF')
    map=nan(size(s_k));
    for k=1:length(s_k)
        delta=abs(g_z-s_k(k));
        [~,z]=min(delta);
        map(k)=z;
    end
    figure;plot(0:255,map);axis([0 255 0 255]);grid on;
    xlabel('输入灰度');ylabel('输出灰度');title('灰度映射曲线')
    
    ImgOut=zeros(size(ImgIn));
    for m=0:length(map)-1
        ImgOut(ImgIn==m)=map(m+1);
    end
    ImgOut=uint8(ImgOut);
    figure;imshow(ImgOut);title('直方图匹配')
    figure;imhist(ImgOut,256);title('直方图匹配');

    输出:只列出转换函数
    这里写图片描述
    转换函数映射图

    二、局部对比度增强

    1. 邻域直方图均衡

    将全局直方图均衡的思想应用于邻域直方图处理中。

    2. 邻域直方图匹配

    将全局直方图匹配的思想应用于邻域直方图处理中。

    3. 邻域统计方法

    a. 基本思想

    对于一幅图像,灰度的均值MG表示平均光照,灰度的方差(或标准差)σG表示对比度的强弱。
    对于图像某一个像素,邻域的灰度均值ML表征邻域光照强度,邻域的方差或者标准差σL表示邻域对比度的强弱。
    根据MLσL的大小自主选择想要增强的点做增强(例如乘以某一个常数E)。

    b. 算法
    1. 初始化:增强常数E,灰度下阈值k0,标准差下阈值 k1,标准差上阈值 k2,窗口半宽s
    2. 计算图像灰度均值MG和灰度标准差σG
    3. 对于每一个像素,计算邻域(大小为2step+1的方块)内灰度均值ML和标准差σL
    4. 如果ML<=k0MG并且k1σG<=σL<=k2σG,将像素灰度乘以E
    c. matlab代码

    测试脚本LocalEnhancement_test.m

    %% 局部对比度增强
    clear all;clc;close all;
    ImgFile='E:\图像处理\冈萨雷斯图片库\DIP3E_Original_Images_CH03\tungsten_original.tif';
    step=1;
    para.E=4.0;
    para.k0=0.4; % 均值下阈值
    para.k1=0.02; % 标准差下阈值
    para.k2=0.4; % 标准差上阈值
    ImgIn=imread(ImgFile);
    ImgHistEq=histeq(ImgIn,256);
    ImgIn=double(ImgIn);
    % ImgIn=double(rgb2gray(ImgIn));
    [ MeanLocal,VarLocal ] = LocalStatistics( ImgIn, step );
    [ ImgOut ] = LocalEnhancement( ImgIn, MeanLocal, VarLocal,para );
    
    figure;imshow(uint8(ImgIn));title('原图');
    figure;imshow(uint8(ImgOut));title('局部统计增强');
    figure;imshow(ImgHistEq);title('全局灰度增强 - 直方图均衡');

    函数LocalEnhancement.m

    function [ ImgOut ] = LocalEnhancement( ImgIn, MeanLocal, VarLocal,para )
    %LOCALENHANCEMENT Summary of this function goes here
    % 使用局部均值和局部标准差实现局部图像增强
    %   Detailed explanation goes here
    [rows, cols]=size(ImgIn);
    MeanGlobal=mean(ImgIn(:));
    VarGlobal=std(ImgIn(:));
    for i=1:rows
        for j=1:cols
            if MeanLocal(i,j)<=para.k0*MeanGlobal...
                    &&VarLocal(i,j)>=para.k1*VarGlobal...
                    &&VarLocal(i,j)<=para.k2*VarGlobal
                ImgIn(i,j)=para.E*ImgIn(i,j);
            end
        end
    end
    ImgOut=ImgIn;
    end
    

    函数LocalStatistics.m

    function [ MeanLocal,VarLocal ] = LocalStatistics( ImgIn, step )
    %LOCALSTATISTICS Summary of this function goes here
    % 求局部的灰度均值灰度方差
    % ImgIn - 输入灰度图,double
    % step  - 窗口大小为2*step+1,step越大,细节越少
    %   Detailed explanation goes here
    % 矩阵边缘补齐
    ImgIn=padarray(ImgIn,[step, step],'replicate');
    [rows, cols] = size(ImgIn);
    MeanLocal=zeros(size(ImgIn));
    VarLocal=zeros(size(ImgIn));
    for i = step+1:1:rows-step
        for j = step+1:1:cols-step
            LocalNeighbor=ImgIn(i-step:i+step,j-step:j+step);
            MeanLocal(i,j)=mean(LocalNeighbor(:));
            VarLocal(i,j)=std(LocalNeighbor(:));
        end
    end
    % 切割成和原图相同的大小
    MeanLocal=MeanLocal(2:end-1,2:end-1);
    VarLocal=VarLocal(2:end-1,2:end-1);
    
    end

    结果输出:
    目的是想要增强右下方的纹理,而不改变中间较亮的纹理。全局灰度增强不但不能增强右下方的纹理,而且改变了中间较亮的纹理。局部统计增强达到了目的,但是产生了一些不想要的假边缘(如左上方)和奇异点(一些散乱的白点)。
    源图像全局HistEQ
    图9. 原图和全局灰度增强的图。全局histeq对右下角纹理的增强效果不明显,而且改变了中间较亮区域的灰度。

    LocalStatistics
    图10. 局部统计增强。右下方纹理得到明显的增强,而且不改变中间较亮区域的纹理。但是产生了一些边缘失真。


    2017.4.24补充:


    直方图均衡和其他的均衡方法都会把图像的直方图尽量调整的分布均匀一些. 尽量不会出现较高的尖峰和较大的灰度空档.这是因为这些算法不知道要增强哪些部分的灰度, 也不知道要去抑制哪些部分的灰度. 而某一部分灰度的增强必然意味着另外一部分灰度的压缩. 所以这些算法只能”雨露均沾”, 把hist中所有的灰度都调整到较为均匀的分布. 雨露均沾的结果, 可能是细节的增强和提升. 也有可能是背景被增强, 造成背景噪声放大, 还不如不增强. 针对后一种情况, 就有了CLAHE等限制对比度的算法.


    1. 本文主要参考冈萨雷斯《数字图像处理》第三版英文版
    2. 如果matlab读入*.tif图片出错,参见:
      http://jingyan.baidu.com/article/aa6a2c14f9441b0d4c19c4b0.html
    展开全文
  • 关于图像增强必须清楚的基本概念 1.图像增强的目的: 1)改善图像的视觉效果, 2)转换为更适合于人或机器分析...1)从处理对象分类:灰度图像,(伪)彩色图像 2)从处理策略分类:全局处理,局部处理(ROI

    关于图像增强必须清楚的基本概念

    1.图像增强的目的:

    1)改善图像的视觉效果,
    2)转换为更适合于人或机器分析处理的形式
    3)突出对人或机器分析有意义的信息
    4)抑制无用信息,提高图像的使用价值
    5)增强后的图像并不一定保真


    2,图像增强的方法分类:

    1)从处理对象分类:灰度图像,(伪)彩色图像
    2)从处理策略分类:全局处理,局部处理(ROI ROI,Region of Interest Interest)
    3)从处理方法分类:空间域(点域运算,即灰度变换;邻域方法,即空域滤波),频域方法
    4)从处理目的分类:图像锐化,平滑去噪,灰度调整(对比度增强)


    3,图像增强的方法之对比度增强

    1)灰度变换法

    线性变换(已实现)
    对数变换(已实现)
    指数变换(已实现)

    2)直方图调整法
    直方图均衡化(已实现)
    直方图匹配(未实现)



    一,直方图均衡化 

    直方图均衡化的英文名称是Histogram Equalization. 

      图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法。直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实现;直方图均衡化则通过使用累积函数对灰度值进行“调整”以实现对比度的增强。
      直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。
      缺点: 
      1)变换后图像的灰度级减少,某些细节消失; 
      2)某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。 
      直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。 
      这种方法通常用来增加许多图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。
      这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景杂讯的对比度并且降低有用信号的对比度。
      

    关于编程实现,同样是不调用matlab库函数,自己编程实现。这样可以更深刻地理解直方图均衡化技术,提高编程能力。

    实现代码(matlab):


    1. clc;  
    2. close all;  
    3. clear all;  
    4.    
    5. src_img = imread('flyman_gray.bmp');    
    6.   
    7. figure (1)   
    8. subplot(321),imshow(src_img),title('原图像');%显示原始图像    
    9. subplot(322),imhist(src_img),title('原图像直方图');%显示原始图像直方图    
    10.   
    11. matlab_eq=histeq(src_img);         %利用matlab的函数直方图均衡化  
    12. subplot(323),imshow(matlab_eq),title('matlab直方图均衡化原图像');%显示原始图像    
    13. subplot(324),imhist(matlab_eq),title('matlab均衡化后的直方图');%显示原始图像直方图   
    14.   
    15. dst_img=myHE(src_img);             %利用自己写的函数直方图均衡化  
    16. subplot(325),imshow(dst_img),title('手写均衡化效果');%显示原始图像    
    17. subplot(326),imhist(dst_img),title('手写均衡化直方图');%显示原始图像直方图   

    直方图均衡化函数的实现:


    1. function dst_img=myHE(src_img)    
    2.   
    3. [height,width] = size(src_img);  
    4. dst_img=uint8(zeros(height,width));  
    5. %进行像素灰度统计;      
    6. NumPixel = zeros(1,256);%统计各灰度数目,共256个灰度级      
    7. for i = 1:height      
    8.     for j = 1: width      
    9.         NumPixel(src_img(i,j) + 1) = NumPixel(src_img(i,j) + 1) + 1;%对应灰度值像素点数量增加一      
    10.     end      
    11. end      
    12. %计算灰度分布密度      
    13. ProbPixel = zeros(1,256);      
    14. for i = 1:256      
    15.     ProbPixel(i) = NumPixel(i) / (height * width * 1.0);      
    16. end      
    17. %计算累计直方图分布      
    18. CumuPixel = zeros(1,256);      
    19. for i = 1:256      
    20.     if i == 1      
    21.         CumuPixel(i) = ProbPixel(i);      
    22.     else      
    23.         CumuPixel(i) = CumuPixel(i - 1) + ProbPixel(i);      
    24.     end      
    25. end      
    26.     
    27. % 指定范围进行均衡化    
    28. % pixel_max=max(max(I));    
    29. % pixel_min=min(min(I));    
    30. pixel_max=255;    
    31. pixel_min=0;    
    32. %对灰度值进行映射(均衡化)      
    33. for i = 1:height      
    34.     for j = 1: width      
    35.         dst_img(i,j) = CumuPixel(src_img(i,j)+1)*(pixel_max-pixel_min)+pixel_min;      
    36.     end      
    37. end      
    38. return;  



    为什们和matlab的直方图不一样呢???



    二,指数变换

    指数变换(Power-Law )的公式:S=c*R^r,通过合理的选择c和r可以压缩灰度范围,算法以c=1.0/255.0, r=2实现。
    要做该图像增强变换需要先做归一化,再指数变换,最后反归一化
    增强效果展示:可以看见,改增强算法并不能很好的将像素尽可能的碾平。
    指数增强参考程序为:
    1. clc;  
    2. close all;  
    3. clear all;   
    4.      
    5. % -------------Gamma Transformations-----------------    
    6. %f = imread('Fig0316(4)(bottom_left).tif');     
    7. f = imread('seed.tif');     
    8. Gamma = 0.4;    
    9. g2 = myExpEnhance(f,Gamma);    
    10.   
    11. figure();    
    12. subplot(221);  imshow(f);  xlabel('a).Original Image');    
    13. subplot(222),imhist(f),title('原图像直方图');%显示原始图像直方图    
    14. subplot(223);  imshow(g2);  xlabel('b).Gamma Transformations \gamma = 0.4');    
    15. subplot(224),imhist(g2),title('增强图像直方图');%显示原始图像直方图   
    指数增强核心函数为:
    1. function dst_img=myExpEnhance(src_img,Gamma)    
    2. src_img = mat2gray(src_img,[0 255]);%将图像矩阵A中介于amin和amax的数据归一化处理, 其余小于amin的元素都变为0, 大于amax的元素都变为1。    
    3. C = 1;    
    4. g2 = C*(src_img.^Gamma);   
    5. %反归一化  
    6. max=255;  
    7. min=0;  
    8. dst_img=uint8(g2*(max-min)+min);  




    三,对数变换

           对数变换主要用于将图像的低灰度值部分扩展,将其高灰度值部分压缩,以达到强调图像低灰度部分的目的。变换方法由下式给出。

    这里的对数变换,底数为(v+1),实际计算的时候,需要用换底公式。其输入范围为归一化的【0-1】,其输出也为【0-1】。对于不同的底数,其对应的变换曲线如下图所示。

    底数越大,对低灰度部分的强调就越强,对高灰度部分的压缩也就越强。相反的,如果想强调高灰度部分,则用反对数函数就可以了。看下面的实验就可以很直观的理解,下图是某图像的二维傅里叶变换图像,其为了使其灰度部分较为明显,一般都会使用灰度变换处理一下。

    效果图:


    参考代码:
    1. clc;  
    2. close all;  
    3. clear all;   
    4.   
    5. %-------------Log Transformations-----------------  
    6. f = imread('seed.tif');  
    7.   
    8. g_1 = myLogEnhance(f,10);  
    9. g_2 = myLogEnhance(f,100);  
    10. g_3 = myLogEnhance(f,200);  
    11.   
    12. figure();  
    13. subplot(2,2,1);  
    14. imshow(f);xlabel('a).Original Image');  
    15.   
    16. subplot(2,2,2);  
    17. imshow(g_1);xlabel('b).Log Transformations v=10');  
    18.   
    19. subplot(2,2,3);  
    20. imshow(g_2);xlabel('c).Log Transformations v=100');  
    21.   
    22. subplot(2,2,4);  
    23. imshow(g_3);  
    24. xlabel('d).Log Transformations v=200');  

    对数变换核心函数
    1. function dst_img=myLogEnhance(src_img,v)   
    2. c=1.0;  
    3. src_img = mat2gray(src_img,[0 255]);  
    4. g =c*log2(1 + v*src_img)/log2(v+1);  
    5. %反归一化  
    6. max=255;  
    7. min=0;  
    8. dst_img=uint8(g*(max-min)+min);  





    四,灰度拉伸

    灰度拉伸也用于强调图像的某个部分,与伽马变换与对数变换不同的是,灰度拉升可以改善图像的动态范围。可以将原来低对比度的图像拉伸为高对比度图像。实现灰度拉升的方法很多,其中最简单的一种就是线性拉伸。而这里介绍的方法稍微复杂一些。灰度拉伸所用数学式如下所示。

    同样的,其输入r为【0-1】,其输出s也为【0-1】。这个式子再熟悉不过了,跟巴特沃斯高通滤波器像极了,其输入输出关系也大致能猜到是个什么形状的。但是,这里就出现一个问题了,输入为0时候,式子无意义了。所以,在用Matlab计算的时候,将其变为如下形式。

    这里的eps,就是Matlab里面,一个很小数。如此做的话,式子变得有意义了。但是,其输入范围为【0-1】的时候,其输出范围变为了。输出范围大致为【0-1】,为了精确起见,使用mat2gray函数将其归一化到精确的[0-1]。调用格式如下。



    五,线性拉伸

    为了突出感兴趣的目标或者灰度区间,相对抑制那些不感兴趣的灰度区域,可采用分段线性法,常用的是三段线性变换




    参考程序:

    1. clc;  
    2. close all;  
    3. clear all;   
    4.   
    5. I=imread('seed.tif');   
    6. [m,n,k]=size(I);  
    7. figure (1)  
    8. imshow('seed.tif');title(' 原图像');   
    9. mid=mean(mean(I));  
    10. %横轴  
    11. fa=20; fb=80;  
    12. %纵轴  
    13. ga=50; gb=230;  
    14.   
    15. J=myLinearEnhance(I,fa,fb,ga,gb);  
    16. figure (2)  
    17. imshow(J);title(' 线性拉伸图像');   
    18.   
    19. pixel_f=1:256;  
    20. pixel_g=zeros(1,256);  
    21.   
    22. %三段斜率,小于1表示该段将会被收缩  
    23. k1=double(ga/fa);   
    24. k2=(gb- ga)/(fb- fa);  
    25. k3=(256- gb)/(256- fb);  
    26. for i=1:256  
    27.     if i <= fa  
    28.         pixel_g(i)= k1*i;  
    29.     elseif fa < i && i <= fb  
    30.         pixel_g(i)= k2*( i- fa)+ ga;  
    31.     else  
    32.         pixel_g(i)= k3*( i - fb)+ gb;  
    33.     end  
    34. end  
    35. figure (3)  
    36. plot(pixel_f,pixel_g);  


    核心函数:

    1. function dst_img=myLinearEnhance(src_img,fa,fb,ga,gb)    
    2.   
    3. [height,width] = size(src_img);  
    4. dst_img=uint8(zeros(height,width));  
    5.   
    6. src_img=double(src_img);  
    7.   
    8. %三段斜率  
    9. k1=ga/fa;   
    10. k2=(gb- ga)/(fb- fa);  
    11. k3=(255- gb)/(255- fb);  
    12. for i=1:height  
    13.     for j=1:width  
    14.             if src_img(i,j) <= fa  
    15.                 dst_img(i,j)= k1*src_img(i,j);  
    16.             elseif fa < src_img(i,j) && src_img(i,j) <= fb  
    17.                 dst_img(i,j)= k2*( src_img(i,j)- fa)+ ga;  
    18.             else  
    19.                 dst_img(i,j)= k3*( src_img(i,j)- fb)+ gb;  
    20.             end  
    21.     end  
    22. end  
    23. dst_img=uint8(dst_img);   




    附录:

    附录网上的另一份讲解:
    直方图均衡化算法分为三个步骤,第一步是统计直方图每个灰度级出现的次数,第二步是累计归一化的直方图,第三步是计算新的像素值。
    第一步:
    for(i=0;i<height;i++)
    for(j=0;j<width;j++)
    n[s[i][j]]++;

    for(i=0;i<L;i++)
    p[i]=n[i]/(width*height);

    这里,n[i]表示的是灰度级为i的像素的个数,L表示的是最大灰度级,width和height分别表示的是原始图像的宽度和高度,所以,p[i]表示的就是灰度级为i的像素在整幅图像中出现的概率(其实就是p[]这个数组存储的就是这幅图像的归一化之后的直方图)。
    第二步:
    for(i=0;i<=L;i++)
    for(j=0;j<=i;j++)
    c[i]+=p[j];

    c[]这个数组存储的就是累计的归一化直方图。
    第三步:
    max=min=s[0][0];
    for(i=0;i<height;i++)
    for(j=0;j<width;j++)
    if(max<s[i][j]){
    max=s[i][j];
    }else if(min>s[i][j]){
    min=s[i][j];
    }

    找出像素的最大值和最小值。
    for(i=0;i<height;i++)
    for(j=0;j<width;j++)
    t[i][j]=c[s[i][j]]*(max-min)+min;

    t[][]就是最终直方图均衡化之后的结果。


    收录优秀代码:

    这份代码写得不错,学习了,原博客地址见参考资源【3】!

    1. #include <stdio.h>  
    2. #include <iostream>  
    3. #include "fftw3.h"  
    4. #include "string"  
    5. #include "vector"  
    6. #include <windows.h>  
    7. #include <opencv2/legacy/legacy.hpp>  
    8. #include <opencv2/nonfree/nonfree.hpp>//opencv_nonfree模块:包含一些拥有专利的算法,如SIFT、SURF函数源码。   
    9. #include "opencv2/core/core.hpp"  
    10. #include "opencv2/features2d/features2d.hpp"  
    11. #include "opencv2/highgui/highgui.hpp"  
    12. #include <opencv2/nonfree/features2d.hpp>  
    13.   
    14. using namespace cv;  
    15. using namespace std;  
    16.   
    17. class hisEqt  
    18. {  
    19. public:  
    20.     hisEqt::hisEqt();  
    21.     hisEqt::~hisEqt();  
    22. public:  
    23.     int w;  
    24.     int h;  
    25.     int nlen;  
    26.   
    27.     int *pHis;  
    28.     float *pdf;  
    29.   
    30.     //=====求像素分布概率密度====    
    31.     void  getPdf();  
    32.   
    33.     //======统计像素个数=======    
    34.     void getHis(unsigned char*imgdata);  
    35.   
    36.     //==========画统计分布直方图===============    
    37.     void drawHistogram(const float*pdf,Mat &hist1);    
    38.   
    39.     //===========直方图均衡化==========    
    40.     void hisBal();  
    41.   
    42.     //====直方图均衡化后的图像===    
    43.     void imgBal(unsigned char* img);  
    44. };  
    45.   
    46.   
    47. hisEqt::hisEqt() :nlen(0){  
    48.     pHis = new int[256 * sizeof(int)];  
    49.     memset(pHis, 0, 256 * sizeof(int));  
    50.     pdf = new float[255 * sizeof(float)];  
    51.     memset(pdf, 0, 255 * sizeof(float));  
    52. }  
    53.   
    54. hisEqt::~hisEqt(){  
    55.     delete[]pHis;  
    56.     delete[]pdf;  
    57. }  
    58.   
    59.   
    60. //======统计像素个数=======    
    61. void hisEqt::getHis(unsigned char*imgdata){  
    62.     for (int i = 0; i<nlen; i++)  
    63.     {  
    64.         pHis[imgdata[i]]++;  
    65.     }  
    66. }  
    67.   
    68.   
    69. //=====求像素分布概率密度====    
    70. void hisEqt::getPdf(){  
    71.     for (int k = 0; k<256; k++)  
    72.     {  
    73.         pdf[k] = pHis[k] / float(nlen);  
    74.     }  
    75. }  
    76.   
    77. //===========直方图均衡化==========    
    78. void hisEqt::hisBal(){  
    79.     for (int k = 1; k<256; k++)  
    80.     {  
    81.         pdf[k] += pdf[k - 1];  
    82.     }  
    83.     for (int k = 0; k<256; k++)  
    84.     {  
    85.         pHis[k] = 255 * pdf[k];  
    86.     }  
    87. }  
    88.   
    89. //====直方图均衡化    
    90. void hisEqt::imgBal(unsigned char* img){  
    91.     for (int i = 0; i<nlen; i++)  
    92.     {  
    93.         img[i] = pHis[img[i]];  
    94.     }  
    95. }  
    96.   
    97.   
    98. void hisEqt::drawHistogram(const float *pdf, Mat& hist1){  
    99.     for (int k = 0; k<256; k++)  
    100.     {  
    101.         if (k % 2 == 0)  
    102.         {  
    103.             Point a(k, 255), b(k, 255 - pdf[k] * 2550);  
    104.             line(hist1,  
    105.                 a,  
    106.                 b,  
    107.                 Scalar(0, 0, 255),  
    108.                 1);  
    109.         }  
    110.         else  
    111.         {  
    112.             Point a(k, 255), b(k, 255 - pdf[k] * 2550);  
    113.             line(hist1,  
    114.                 a,  
    115.                 b,  
    116.                 Scalar(0, 255, 0),  
    117.                 1);  
    118.         }  
    119.     }  
    120. }  
    121.   
    122.   
    123. int main()  
    124. {  
    125.     Mat image = imread("Fig0651(a)(flower_no_compression).tif");  
    126.     if (!image.data)  
    127.         return -1;  
    128.   
    129.     Mat hist2(256, 256, CV_8UC3, Scalar(0, 0, 0));  
    130.     Mat hist1(256, 256, CV_8UC3, Scalar(0, 0, 0));  
    131.   
    132.     Mat imgOut = Mat(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));  
    133.     vector<Mat> planes;  
    134.     int chn = image.channels();  
    135.     if (chn == 3)  
    136.     {  
    137.         split(image, planes);  
    138.     }  
    139.     while (chn)  
    140.     {  
    141.         chn--;  
    142.         unsigned char* imageData = new unsigned char[sizeof(unsigned char)*(image.cols*image.rows)];  
    143.         memcpy(imageData, planes[chn].data, planes[chn].cols*planes[chn].rows);  
    144.         hisEqt his;//自定义的类  
    145.         his.nlen = image.rows*image.cols;  
    146.         his.getHis(imageData);  
    147.         his.getPdf();  
    148.   
    149.         //  //======画原图直方图并保存============    
    150.         his.drawHistogram(his.pdf, hist1);  
    151.         string pic_name = "hisline";  
    152.         pic_name = pic_name + to_string(chn);  
    153.         pic_name=pic_name+  ".jpg";  
    154.         imwrite(pic_name, hist1);  
    155.   
    156.         his.hisBal();  
    157.         his.getPdf();  
    158.         //  //======画均衡化后直方图并保存============    
    159.         his.drawHistogram(his.pdf, hist2);  
    160.         string pic_name0 = "his_balanceline";  
    161.         pic_name0 = pic_name0 + to_string(chn);  
    162.         pic_name0 = pic_name0 + ".jpg";  
    163.         imwrite(pic_name0, hist2);  
    164.   
    165.         //  //=====图像均衡化===    
    166.         his.imgBal(imageData);  
    167.         memcpy(planes[chn].data, imageData, planes[chn].cols*planes[chn].rows);  
    168.         delete[] imageData;  
    169.         imageData = NULL;  
    170.     }  
    171.     merge(planes, imgOut);//单通道合并  
    172.     imwrite("result.jpg", imgOut);  
    173.     return 0;  
    174. }  
    展开全文
  • 最近在制作一个安卓上的图像处理软件,感觉调整对比度这个功能,在photoshop上还是比较常用的功能,于是就在软件上加上这个功能。 对比度的定义:简单的来说就是使亮的地方更亮,暗的地方更暗。 但是关于亮与...

    最近在制作一个安卓上的图像处理软件,感觉调整对比度这个功能,在photoshop上还是比较常用的功能,于是就在软件上加上这个功能。

    对比度的定义:简单的来说就是使亮的地方更亮,暗的地方更暗。

    但是关于亮与暗的解释有很多种,在RGB模式中,要使图片变亮的方法是提高R,G,B三个通道的值,从而使图片看起来更亮。

     

    网上最常用的调整对比度的算法是根据图像的灰度进行调整

    下面是算法:

     

    1、计算平均亮度

    2、每点与平均亮度比较,得到差值。

    3、新的亮度 = 平均亮度 + 系数 *  差值

    4、根据新的亮度,计算出新的rgb(保持色调不变)

     

    这里亮度就是图像的灰度 亮度的计算方法具体请参考RGB色转为灰度色算法

    就算出新的RGB颜色,保持色调不变,只需要保持RGB通道的比例不变就行

    关于3的公式,有的是 新的亮度 = 此点的亮度 + 系数 * 此点的亮度 * 差值 但两个公式处理出来的效果差不多,下面放出分别用两个公式的效果图

    数字图像处理 <wbr>调整对比度的几种方法

    此为 新的亮度 = 平均亮度 + 系数 * 差值 的结果

     

    数字图像处理 <wbr>调整对比度的几种方法

    此为 新的亮度 = 此点的亮度 + 系数 * 此点的亮度 * 差值 的结果

     

    数字图像处理 <wbr>调整对比度的几种方法

    此为原图

     

    数字图像处理 <wbr>调整对比度的几种方法

    此为Photoshop 中提高对比度后的结果

     

    可以看到用这种方法处理出来的结果和PS的结果相差甚远,很不能令人满意

     

    于是我对PS调整对比度的结果进行分析

    发现当调整对比度时,Lab通道的 a与b通道的值并不改变,改变的只是L(明度)的大小,而不是像RGB一样,调整对比度后R,G,B通道的值都发生变化

    数字图像处理 <wbr>调整对比度的几种方法

    L通道直方图,灰色为调整前,黑色为调整后

    数字图像处理 <wbr>调整对比度的几种方法

    a通道,可以发现调整前后无变化

    数字图像处理 <wbr>调整对比度的几种方法

    b通道,调整前后无变化

    对L通道的直方图加以分析,发现明度的变化有以下规则(假设明度最大值为1):


    明度大于0.5的像素,增加其明度

    明度小于0.5的像素,减小其明度

    与平均明度并无关系

    明度的增加/减小 偏移量由低到高再降低,可以将此简单的认为是一个抛物线,抛物线的两个焦点分别为

    (0.5,1) 明度>0.5

    (0,0.5) 明度<0.5

     

    公式为

    新的明度=(明度-0.5)*(明度-1)*系数+明度   明度>0.5

    新的明度=-(明度-0.5)*(明度-0)*系数+明度  明度<0.5

     

    利用此方法处理后的图像效果如下

    数字图像处理 <wbr>调整对比度的几种方法

     

    效果很不错~ 保持了原有色调的同时提高了对比度,并且与PS的效果相近,不过对于暗的部分处理不明显,可以通过增加对暗部分的系数来修正

     

    不过采用次方法有个很大的缺点:运算复杂

    使用此方法需要消耗多于第一个方法好几倍的时间和空间

    举个例子

    一张 1080*1528 像素的图片用此方法处理

    需要用到600M的内存,并在在我的电脑上需要跑3秒以上的时间

    相对于现在手机支持的分辨率而言,1080*1528并不大,但一般的手机却并不具有这么大的内存与能和台式机匹敌的计算功能。所以这个方法并不实用。

     

    之所以这个方法如此复杂,是因为需要处理前需要将RGB模式转换为Lab模式,在Lab模式下处理图像,处理完后还需要重新转换为RGB模式以便输出,然而RGB转Lab的算法太过复杂。

     

    在此基础上寻求另一种调整对比度的方法

    HSV颜色空间中,颜色由色调、饱和度和明度三个分量确定。

    可以试着保持色调和饱和度不变,通过调整明度来改变图像的对比度。

    利用此方法的优点是:实现简单,RGB到HSV能过进行快速的变换,而且调整的同时只改变了明度的大小,能够保证色调与调整前一致。不需要像方法二一样的空间与时间

    下面是利用HSV空间调整的效果

    数字图像处理 <wbr>调整对比度的几种方法

    与PS的结果有点偏差,但就效果而言比方法一好多了

     

    一直想在手机上做个能让自己满意的图像处理工具。昨天花了一整天的时间在搞对比度的处理。

    将这些心得与同是对数字图像处理有爱的人分享。

    最后就懒得发代码了,写这博文花了两小时 (┳_┳)... 累

    如果有需要源码的可以私信或者发邮件amethystarry@gmail.com

     

    谢谢!!☆⌒(*^-゜)v

    展开全文
  • 阈值作为对比度调整依据,当对比度调整为-1时,图像RGB各分量都等于阀值,图像呈全灰色,灰度图上只有一种颜色,即阀值灰度。其算法实现如下: 1) 比较当前像素点三维颜色值与阈值的大小,并获取其差值。 2) 当...

    对比度调整算法说明(完整python代码在文末)

    本算法主要是对RGB空间进行调整。设定合适的RGB阈值,并在此阈值基础上计算出合适的调整系数进行对比度调整。阈值作为对比度调整依据,当对比度调整为-1时,图像RGB各分量都等于阀值,图像呈全灰色,灰度图上只有一种颜色,即阀值灰度。其算法实现如下:
        1) 比较当前像素点三维颜色值与阈值的大小,并获取其差值。
        2) 当增大对比度时,利用调整系数来指数的放大差值;当减小对比度时,利用调整系数来线性的减小差值;当对比度增量为-1时,差值即减小为0。
        例如:当前像素点为(50,200,250),阈值为200;对比度增大后可能为(10,200,255),对比度减小后可能为(150,200,210)。
      (不明白可以的,可以参考CSDN博客:https://blog.csdn.net/maozefa/article/details/7069001

     

    完整python代码如下:

    运行方式:打开终端界面,在该py文件目录下,运行:python  该文件.py  图片路径  对比度等级(-1~1)  阈值(默认0.5,可忽略)

    例如:python  Contrast.py  C:\Users\PDD\Desktop\pdd.jpg  0.8 (0.5)

    import cv2
    import sys
    import numpy as np
    import matplotlib.pyplot as plt
    
    """
      对比度调整算法:
      主要是对RGB空间进行调整。设定合适的RGB阈值,并在此阈值基础上计算出合适的调整系数进行对比度调整。
      参考CSDN博客:https://blog.csdn.net/maozefa/article/details/7069001
    """
    def ContrastAlgorithm(rgb_img, contrast=0.5, threshold=0.5):
        img = rgb_img * 1.0
        img_out = img
        
        # 增量等于1,按灰度阈值最多调整成八种颜色:
        # 黑、红、绿、蓝、黄(255,255,0)、品红(255,0,255)、青(0,255,255)、白
        if contrast == 1:
            # newRGB = RGB >= Threshold? 255 : 0
            mask_1 = img >= threshold*255.0
            rgb1 = 255.0
            rgb2 = 0
            img_out = rgb1 * mask_1 + rgb2 * (1 - mask_1)
        
        # 增量大于0小于1
        elif contrast >= 0 :
            alpha = 1 - contrast
            alpha = 1/alpha - 1
            img_out[:, :, 0] = img[:, :, 0] + (img[:, :, 0] - threshold * 255.0) * alpha
            img_out[:, :, 1] = img[:, :, 1] + (img[:, :, 1] - threshold * 255.0) * alpha
            img_out[:, :, 2] = img[:, :, 2] + (img[:, :, 2] - threshold * 255.0) * alpha
            
        # 增量小于0
        else:
            alpha = contrast
            img_out[:, :, 0] = img[:, :, 0] + (img[:, :, 0] - threshold * 255.0) * alpha
            img_out[:, :, 1] = img[:, :, 1] + (img[:, :, 1] - threshold * 255.0) * alpha
            img_out[:, :, 2] = img[:, :, 2] + (img[:, :, 2] - threshold * 255.0) * alpha
        
        img_out = img_out/255.0
        return img_out
    
    path = './resource/fruit.bmp'
    contrast = 0.5   # 范围:-1至1
    threshold = 0.5   # 范围:0至1
    
    #  run : python Contrast.py (path) (contrast) (threshold)
    if __name__ == "__main__":
        len = len(sys.argv)
        if len >= 2 :
            path = sys.argv[1]
            if len >= 3 :
                contrast = float(sys.argv[2])
                if len >= 4 :
                    threshold = float(sys.argv[3])
    
        img = cv2.imread(path)
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        img_new = ContrastAlgorithm(img, contrast, threshold)
    
        plt.figure("img_original")
        plt.imshow(img/255.0)
        plt.axis('off')
    
        plt.figure("img_contrast")
        plt.imshow(img_new)
        plt.axis('off')
    
        plt.show() 

     

     

     

    展开全文
  • 假设一副图像的色彩模型是rgb,那么每个像素占24bit(不考虑压缩),r,g,b各占8bit,值从0~255。全0是黑,全255是白。 当r,g,b值相等时,是一条灰色渐变带,如(50,50,50) ,(127,127,127)等等。 每个像素点从...

    网上有很多资料,在这里讲讲自己的理解。

    一、概念。

    a.rgb

    假设一副图像的色彩模型是rgb,那么每个像素占24bit(不考虑压缩),r,g,b各占8bit,值从0~255。全0是黑,全255是白。

    当r,g,b值相等时,是一条灰色渐变带,如(50,50,50)  ,(127,127,127)等等。

    每个像素点从视觉来看有其对应的亮度值,r,g,b等量的相加或减少,可以改变这个点的亮度,而不改变色相,这便是调节亮度的原理。

    b.对比度

    对比度反应了图片上亮区域和暗区域的层次感。而反应到图像编辑上,调整对比度就是在保证平均亮度不变的情况下,扩大或缩小亮的点和暗的点之间的差异。

     

    二、算法

    给个photoshop调节对比度的公式,

    nRGB = RGB + (RGB - Threshold) * Contrast / 255

    其中nRGB代表了r,g,b各自重新计算后的值。Threshold是平均亮度,一般我们不会特意算图像的平均亮度,一来耗时,二来大部分图片是在100~150之间。我们取127,与实际相近。Contrast取值范围为[-255,255]。

    所以当Contrast为0时,rgb值不变,表示当前的一个对比度。

    为-255时,rgb都为127,亮度都一样,没有差别,呈灰色。

    为255时,在Threshold之上的像素点会变得更亮,反之变得更暗。

    展开全文
  • 设计一个Sigmoid函数,实现对图像对比度调整; 使用opencv窗口系统的slider控件,交互改变Sigmoid函数的参数,实现不同程度的对比度调整; 2.方法 一次函数方法 想要调整图片的对比度,就要对图片中的像素进行...
  • 图像处理调整亮度与对比度   很多时候,一张图像被过度曝光显得很白,或者光线不足显得很暗,有时候背景跟图像人物 也观察不清楚,这个时候可以通过调节图像的两个基本属性-亮度与对比度来获得整体效果 ...
  • 对比度是数字图像中非常基本的概念,一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,即指一幅图像灰度反差的大小。直白的说就是:对比度大整体的色彩更鲜艳,对比度小色彩感更平淡。接下来我们用像素...
  • 图像处理软件Photoshop中有一个自动对比度功能,可以一键调节图像亮度、对比度。比如,像下面这张由于曝光不足形成的非常暗的图像,只有图像中间比较亮一些的路面才能看到,其他地面上的物体几乎无法看见。 ...
  • 阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。... 在《Delphi图像处理 -- 亮度/对比度调整》一文实现了P
  • 关于图像对比度【5】——局部自适应对比度调整之前说的对比度都是对整幅图像来说的,在进行对比度调整的时候,也是对整幅图像使用了相同的参数,比如用线性变换的方法来做对比度调整,即y=kx+b,对于所有的像素点k和...
  • 调整图像亮度和对比度属于像素变换-点操作 g(i,j) = αf(i,j) +β (其中 α>0 ,α 增益(放大倍数),用来控制图像对比度,β (偏置),用控制图像的亮度 参考代码: #include <iostream> #include &...
  • 今天呢,我们一起学习一下,如何调整图像对比度以及亮度。 一、原理 调整图像亮度与对比度所用的公式 g(i,j) = a * f(i,j) + b 其中,i 和 j 表示像素位于第i行 和 第j列 。 参数f(i,j)表示源图像像素。 ...
  • 其实在图像处理中,拉开对比度是最重要的一项。常用的拉开对比度方式和使用算子如下: 1.将RGB图像拆分通道 算子:decompose3()将RGB图像拆分成三个通道 R G B,数字3表示按照3通道拆分 -> trans_from_...
  • 图像编辑之对比度调整 亮度对比度的算法公式
  • 图像亮度与对比度调整,是放在skimage包的exposure模块里面 1、gamma调整 原理:I=Ig 对原图像的像素,进行幂运算,得到新的像素值。公式中的g就是gamma值。 如果gamma&gt;1, 新图像比原图像暗 如果gamma...
  • 很多时候,一张图像被过度曝光显得很白,或者光线不足显得很暗,有时候背景跟图像人物也观察不清楚,这个时候可以通过调节图像的两个基本属性-亮度与对比度来获得整体效果的提升,从而得到质量更高的图片。...
  • 本文将介绍数字图像处理中两个基本内容---图像亮度对比度,详细讲解两种基本的亮度对比度调节算法,并使用C语言进行算法实现,在教会初学者算法的同时,不依赖任何第三方库编程实现,学以致用且易学易用。
  • 对比度增强 提前规定:输入图像
1 2 3 4 5 ... 20
收藏数 26,674
精华内容 10,669