Контрастная корректировка

В этом примере показано, как сгенерировать HDL-код из проекта MATLAB®, который настраивает контрастность изображений путем линейного масштабирования пиксельных значений.

Алгоритм

Контрастная корректировка настраивает контраст изображения путем линейного масштабирования пиксельных значений между верхним и нижними пределами. Пиксельные значения, которые являются выше или ниже этой области значений, насыщаются к верхнему значению или значению нижнего предела, соответственно.

Проект MATLAB

design_name = 'mlhdlc_image_scale';
testbench_name = 'mlhdlc_image_scale_tb';

Давайте смотреть на проект MATLAB

type(design_name);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% scale.m
%
% Adjust image contrast by linearly scaling pixel values. 
%
% The input pixel value range has 14bits and output pixel value range is
% 8bits.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [x_out, y_out, pixel_out] = ...
    mlhdlc_image_scale(x_in, y_in, pixel_in, ...
          damping_factor_in, dynamic_range_in, ...
          tail_size_in, max_gain_in, ...
          width, height)

%   Copyright 2011-2015 The MathWorks, Inc.

persistent histogram1 histogram2
persistent low_count
persistent high_count
persistent offset
persistent gain
persistent limits_done
persistent damping_done
persistent reset_hist_done
persistent scaling_done
persistent hist_ind
persistent tail_high
persistent min_hist_damped    %Damped lower limit of populated histogram
persistent max_hist_damped    %Damped upper limit of populated histogram
persistent found_high
persistent found_low

DR_PER_BIN          = 8;
SF                  = 1./(1:(2^14/8)); % be nice to fix this
NR_OF_BINS          = (2^14/DR_PER_BIN) - 1;
MAX_DF              = 255;

if isempty(offset)
    offset               = 1;
    gain                 = 1;
    limits_done          = 1;
    damping_done         = 1;
    reset_hist_done      = 1;
    scaling_done         = 1;
    hist_ind             = 1;
    tail_high            = NR_OF_BINS;
    low_count 			 = 0;
    high_count 			 = 0;
    min_hist_damped      = 0;
    max_hist_damped      = (2^14/DR_PER_BIN) - 1;
    found_high           = 0;
    found_low            = 0;
end
if isempty(histogram1)
    histogram1           = zeros(1, NR_OF_BINS+1);
    histogram2           = zeros(1, NR_OF_BINS+1);
end

if y_in < height
    frame_valid = 1;
    if x_in < width
        line_valid = 1;
    else
        line_valid = 0;
    end
else
    frame_valid = 0;
    line_valid = 0;
end

% initialize at beginning of frame
if x_in == 0 && y_in == 0
    limits_done = 0;
    damping_done = 0;
    reset_hist_done = 0;
    scaling_done = 0;
    low_count = 0;
    high_count = 0;
    hist_ind = 1;
end

max_gain_frac = max_gain_in/2^4;
pix11 = floor(pixel_in/DR_PER_BIN);
pix_out_temp = pixel_in;

%**************************************************************************
%Check if valid part of frame. If pixel is valid remap pixel to desired
%output dynamic range (dynamic_range_in) by subtracting the damped offset
%(min_hist_damped) and applying the calculated gain calculated from the
%previous frame histogram statistics.
%**************************************************************************
% histogram read
histReadIndex1 = 1;
histReadIndex2 = 1;
if frame_valid && line_valid
    histReadIndex1 = pix11+1;
    histReadIndex2 = pix11+1;
elseif ~limits_done
    histReadIndex1 = hist_ind;
    histReadIndex2 = NR_OF_BINS - hist_ind;
end
histReadValue1 = histogram1(histReadIndex1);
histReadValue2 = histogram2(histReadIndex2);
histWriteIndex1 = NR_OF_BINS+1;
histWriteIndex2 = NR_OF_BINS+1;
histWriteValue1 = 0;
histWriteValue2 = 0;
if frame_valid
    if line_valid
        temp_sum = histReadValue1 + 1;
        ind = min(pix11+1, NR_OF_BINS);
        val = min(temp_sum, tail_size_in);
        histWriteIndex1 = ind;
        histWriteValue1 = val;
        histWriteIndex2 = ind;
        histWriteValue2 = val;
        
        %Scale pixel
        pix_out_offs_corr = pixel_in - min_hist_damped*DR_PER_BIN;
        pix_out_scaled = pix_out_offs_corr * gain;
        pix_out_clamp = max(min(dynamic_range_in, pix_out_scaled), 0);
        pix_out_temp = pix_out_clamp;
    end
else
    %**********************************************************************
    %Ignore tail_size_in pixels and find lower and upper limits of the
    %histogram.
    %**********************************************************************
    if ~limits_done
        if hist_ind == 1
            tail_high = NR_OF_BINS-1;
            offset = 1;
            found_high = 0;
            found_low = 0;
        end
        
        low_count = low_count + histReadValue1;
        hist_ind_high = NR_OF_BINS - hist_ind;
        high_count = high_count + histReadValue2;
        
        %Found enough high outliers
        if high_count > tail_size_in && ~found_high
            tail_high = hist_ind_high;
            found_high = 1;
        end
        
        %Found enough low outliers
        if low_count > tail_size_in && ~found_low
            offset = hist_ind;
            found_low = 1;
        end
        
        hist_ind = hist_ind + 1;
        %All bins checked so limits must already be found
        if hist_ind >= NR_OF_BINS
            hist_ind = 1;
            limits_done = 1;
        end
        %**********************************************************************
        %Damp the limit change to avoid image flickering. Code below equivalent
        %to: max_hist_damped = damping_factor_in*max_hist_dampedOld +
        %(1-damping_factor_in)*max_hist_dampedNew;
        %**********************************************************************
    elseif ~damping_done
        min_hist_weighted_old = damping_factor_in*min_hist_damped;
        min_hist_weighted_new = (MAX_DF-damping_factor_in+1)*offset;
        min_hist_weighted = (min_hist_weighted_old + ...
            min_hist_weighted_new)/256;
        min_hist_damped = max(0, min_hist_weighted);
        max_hist_weighted_old = damping_factor_in*max_hist_damped;
        max_hist_weighted_new = (MAX_DF-damping_factor_in+1)*tail_high;
        max_hist_weighted = (max_hist_weighted_old + ...
            max_hist_weighted_new)/256;
        max_hist_damped = min(NR_OF_BINS, max_hist_weighted);
        damping_done = 1;
        hist_ind = 1;
        %**********************************************************************
        %Reset all bins to zero. More than one bin can be reset per function
        %call if blanking time is too short.
        %**********************************************************************
    elseif ~reset_hist_done
        histWriteIndex1 = hist_ind;
        histWriteValue1 = 0;
        histWriteIndex2 = hist_ind;
        histWriteValue2 = 0;
        hist_ind = hist_ind+1;
        if hist_ind == NR_OF_BINS
            reset_hist_done = 1;
        end
        %**********************************************************************
        %The gain factor is determined by comparing the measured damped actual
        %dynamic range to the desired user specified dynamic range. Input
        %dynamic range is measured in bins over DR_PER_BIN space.
        %**********************************************************************
    elseif ~scaling_done
        dr_in = round(max_hist_damped - min_hist_damped);
        gain_temp = dynamic_range_in*SF(dr_in);
        gain_scaled = gain_temp/DR_PER_BIN;
        gain = min(max_gain_frac, gain_scaled);
        scaling_done = 1;
        hist_ind = 1;
    end
end
histogram1(histWriteIndex1) = histWriteValue1;
histogram2(histWriteIndex2) = histWriteValue2;

x_out = x_in;
y_out = y_in;
pixel_out = pix_out_temp;
type(testbench_name);
%Test bench for scaling, analogous to automatic gain control (AGC)

%   Copyright 2011-2018 The MathWorks, Inc.

testFile = 'mlhdlc_img_peppers.png';
imgOrig = imread(testFile);
[height, width] = size(imgOrig);
imgOut = zeros(height,width);
hBlank = 20;
% make sure we have enough vertical blanking to filter the histogram
vBlank = ceil(2^14/(width+hBlank));

%df - Temporal damping factor of rescaling
%dr - Desired output dynamic range
df = 0; 
dr = 255; 
nrOfOutliers = 248;
maxGain = 2*2^4;

for frame = 1:2
    disp(['frame: ', num2str(frame)]);
    for y_in = 0:height+vBlank-1       
        %disp(['frame: ', num2str(frame), ' of 2, row: ', num2str(y_in)]);
        for x_in = 0:width+hBlank-1
            if x_in < width && y_in < height
                pixel_in = double(imgOrig(y_in+1, x_in+1));
            else
                pixel_in = 0;
            end
            
            [x_out, y_out, pixel_out] = ...
                mlhdlc_image_scale(x_in, y_in, pixel_in, df, dr, ...
                    nrOfOutliers, maxGain, width, height);
                       
            if x_out < width && y_out < height
                imgOut(y_out+1,x_out+1) = pixel_out;
            end
        end
    end
    
    figure('Name', [mfilename, '_scale_plot']);
    imgOut = round(255*imgOut/max(max(imgOut)));
    subplot(2,2,1); imshow(imgOrig, []);
    title('Original Image');
    subplot(2,2,2); imshow(imgOut, []);
    title('Scaled Image');
    subplot(2,2,3); histogram(double(imgOrig(:)),2^14-1);
    axis([0, 255, 0, 1500]);
    title('Histogram of original Image');
    subplot(2,2,4); histogram(double(imgOut(:)),2^14-1);
    axis([0, 255, 0, 1500]);
    title('Histogram of equalized Image');
end

Симулируйте проект

Это - хорошая практика, чтобы симулировать проект с испытательным стендом до генерации кода, чтобы убедиться, что нет никаких ошибок периода выполнения.

mlhdlc_image_scale_tb
frame: 1
frame: 2

Setup для примера

Выполните следующие строки кода, чтобы скопировать необходимые файлы в качестве примера во временную папку.

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_scale'];

% create a temporary folder and copy the MATLAB files
cd(tempdir);
[~, ~, ~] = rmdir(mlhdlc_temp_dir, 's');
mkdir(mlhdlc_temp_dir);
cd(mlhdlc_temp_dir);

% copy files to the temp dir
copyfile(fullfile(mlhdlc_demo_dir, [design_name,'.m*']), mlhdlc_temp_dir);
copyfile(fullfile(mlhdlc_demo_dir, [testbench_name,'.m*']), mlhdlc_temp_dir);
copyfile(fullfile(mlhdlc_demo_dir, 'mlhdlc_img_peppers.png'), mlhdlc_temp_dir);

Создайте новый проект HDL Coder™

coder -hdlcoder -new mlhdlc_scale_prj

Затем добавьте файл 'mlhdlc_image_scale.m' в проект как функция MATLAB и 'mlhdlc_image_scale_tb.m' как Испытательный стенд MATLAB.

Можно обратиться к Началу работы с MATLAB к примеру по Рабочему процессу HDL для более полного примера при создании и заполнении проектов HDL Coder MATLAB.

Запустите преобразование фиксированной точки и генерацию HDL-кода

Запустите Советника по вопросам Рабочего процесса от вкладки Build, и щелчок правой кнопкой по 'Генерации кода' продвигаются и выбирают опцию, 'Запущенную к выбранной задаче', чтобы запустить все шаги с начала через генерацию HDL-кода.

Исследуйте сгенерированный HDL-код путем нажатия на гиперссылки в окне Code Generation Log.

Очистите Сгенерированные Файлы

Можно запустить следующие команды, чтобы очистить временную папку проекта.

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_scale'];
clear mex;
cd (mlhdlc_demo_dir);
rmdir(mlhdlc_temp_dir, 's');