对遥感图像进行2%线性拉伸

遥感图像数据大多为16位,在显示时要将其拉伸到0-255的区间范围,ENVI软件打开图像时默认使用2%的线性拉伸,思路是将直方图累积在2%和98%之间的像元值拉伸,取直方图累积在2%处对应的光谱值为MinValue,98%处对应的光谱值为MaxValue,那么可解释为如果像元值大于MinValue且小于MaxValue,则将其拉伸至0-255;如果像元值小于MinValue,那么将其改为MinValue;如果像元值大于MaxValue,那么将其改为255。

下面给出一个对直方图进行2%线性拉伸的例子

利用GDAL可以使用函数poBand->GetHistogram来得到波段的直方图,然后对直方图进行计算进行线性拉伸,并不复杂。

下面给出2%线性拉伸的Matlab代码供参考

cal_lr_val.m文件,对于输入的直方图,计算拉伸时应取的左值和右值

% ------------------------------------
% 计算直方图左右裁剪的灰度值
% 2015/07/01
%
% Input histcount --> 直方图
% tt --> 图像像素个数
% per --> 左右裁剪的百分比
% 
% Output l_val --> 左值
% r_val --> 右值
% ------------------------------------

function [l_val, r_val] = calc_lr_val(histcount, tt, per)

    fprintf(' ... ... ... ... ... ... ... ... ...\n');
    fprintf(' ... CALC LEFT AND RIGHT VALUE \n');

    per_tt = tt*per;  % 按百分比裁剪的像素个数 

    % 计算左值
    tmp = 0;
    for i = 1:length(histcount)
        tmp = tmp + histcount(i);
        if tmp >= per_tt
            l_val = i;
            break;
        end
    end
    % 计算右值
    tmp = 0;
    for i = 1:length(histcount)
        tmp = tmp + histcount(length(histcount)-i+1);
        if tmp >= per_tt
            r_val = length(histcount)-i+1;
            break;
        end
    end

    fprintf(' ... Stretch Percentage is %d%%\n', per*100);
    fprintf(' ... Left Val is %d \n', l_val);
    fprintf(' ... Right Val is %d \n', r_val);
    fprintf(' ... ... ... ... ... ... ... ... ...\n\n');

return

img_map.m文件,根据计算的左值和右值,将16位图像拉伸,输出为8位图像

% ------------------------------------
% 将图像映射至 [0, 255] 区间
% 2015/07/01
%
% Input img_16bit --> 16位原图像
% l_val --> 映射左值
% r_val --> 映射右值
% 
% Output img_8bit --> 输出8位拉伸后图像
% ------------------------------------

function [img_8bit] = img_map(img_16bit, l_val, r_val)

    [xlen, ylen, c] = size(img_16bit);
    img_8bit = zeros(xlen, ylen);

    fprintf(' ... ... ... ... ... ... ... ... ...\n');
    fprintf(' ... IMG MAPPING FROM 16BIT TO 8BIT \n');    
    fprintf(' ... Img mapping begin ... ... \n');

    % 按照左右值映射
    img_8bit = (img_16bit - l_val).*(255/(r_val-l_val));
    img_8bit = uint8(round(img_8bit));


    fprintf(' ... Img mapping finshied !!! !!! \n\n');

return

main.m 程序的主文件

fprintf(' ... Read Imagery ... ...\n');
img = imread('./Img/test_pic_1.tif');

% 这里默认输入图像为单通道
[ylen, xlen] = size(img);
fprintf(' ... Img Xlen: %d pixels\n', xlen);
fprintf(' ... Img Ylen: %d pixels\n\n\n', ylen);

% 线性拉伸
max_val = max(img(:));
min_val = min(img(:));
fprintf(' ... ... ... ... ... ... ... ... ... ...\n');
fprintf(' ... Min Val is %d \n', min_val);
fprintf(' ... Max Val is %d \n', max_val);
fprintf(' ... ... ... ... ... ... ... ... ... ...\n\n');

% 统计直方图
% 输入图像为16位,取值范围为 0 到 65535
bins = 0:65535;
histcount = histc(img(:)', bins); 
%清除临时变量 
clear bins max_val min_val; 
% 直方图裁剪,计算左值和右值 
[l_val, r_val] = calc_lr_val(histcount, xlen*ylen, 0.02); 
% 根据左值和右值,将图像由16位映射至8位 
img_8bit = img_map(img, l_val, r_val); 
% 保存结果 
imwrite(img_8bit, 'res.png');

return

 

参考链接:http://www.voidcn.com/article/p-ethxsjor-du.html

你可能感兴趣的:(图像处理算法相关,图像处理,图像拉伸,16bit转8bit)