Генерация HDL-кода для адаптивного медианного фильтра

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

Адаптивный фильтр MATLAB Design

Адаптивный медианный фильтр выполняет пространственную обработку, чтобы уменьшить шум в изображении. Фильтр сравнивает каждый пиксель в изображении с окружающими пикселями. Если одно из значений пикселей значительно отличается от большинства окружающих пикселей, пиксель рассматривается как шум. Алгоритм фильтрации затем заменяет шумовой пиксель на медианные значения окружающих пикселей. Этот процесс повторяется до тех пор, пока не будут удалены все шумовые пиксели в изображении.

design_name = 'mlhdlc_median_filter';
testbench_name = 'mlhdlc_median_filter_tb';

Проверьте проект MATLAB:

edit(design_name);
%#codegen
function [pixel_val, pixel_valid] = mlhdlc_median_filter(c_data, c_idx)
%   Copyright 2011-2019 The MathWorks, Inc.

smax = 9;
persistent window;
if isempty(window)
    window = zeros(smax, smax);
end

cp = ceil(smax/2); % center pixel;

w3 = -1:1;
w5 = -2:2;
w7 = -3:3;
w9 = -4:4;

r3 = cp + w3;      % 3x3 window
r5 = cp + w5;      % 5x5 window
r7 = cp + w7;      % 7x7 window
r9 = cp + w9;      % 9x9 window

d3x3 = window(r3, r3);
d5x5 = window(r5, r5);
d7x7 = window(r7, r7);
d9x9 = window(r9, r9);

center_pixel = window(cp, cp);


% use 1D filter for 3x3 region
outbuf = get_median_1d(d3x3(:)');
[min3, med3, max3] = getMinMaxMed_1d(outbuf);

% use 2D filter for 5x5 region
outbuf = get_median_2d(d5x5);
[min5, med5, max5] = getMinMaxMed_2d(outbuf);

% use 2D filter for 7x7 region
outbuf = get_median_2d(d7x7);
[min7, med7, max7] = getMinMaxMed_2d(outbuf);

% use 2D filter for 9x9 region
outbuf = get_median_2d(d9x9);
[min9, med9, max9] = getMinMaxMed_2d(outbuf);


pixel_val = get_new_pixel(min3, med3, max3, ...
    min5, med5, max5, ...
    min7, med7, max7, ...
    min9, med9, max9, ...
    center_pixel);


% we need to wait until 9 cycles for the buffer to fill up
% output is not valid every time we start from col1 for 9 cycles.
persistent datavalid
if isempty(datavalid)
    datavalid = false;
end
pixel_valid = datavalid;
datavalid = (c_idx >= smax);


% build the 9x9 buffer
window(:,2:smax) = window(:,1:smax-1);
window(:,1) = c_data;

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [min, med, max] = getMinMaxMed_1d(inbuf)

max = inbuf(1);
med = inbuf(ceil(numel(inbuf)/2));
min = inbuf(numel(inbuf));

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [min, med, max] = getMinMaxMed_2d(inbuf)

[nrows, ncols] = size(inbuf);
max = inbuf(1, 1);
med = inbuf(ceil(nrows/2), ceil(ncols/2));
min = inbuf(nrows, ncols);

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function new_pixel  = get_new_pixel(...
    min3, med3, max3, ...
    min5, med5, max5, ...
    min7, med7, max7, ...
    min9, med9, max9, ...
    center_data)

if (med3 > min3 && med3 < max3)
    new_pixel = get_center_data(min3, med3, max3,center_data);
elseif (med5 > min5 && med5 < max5)
    new_pixel = get_center_data(min5, med5, max5,center_data);
elseif (med7 > min7 && med7 < max7)
    new_pixel = get_center_data(min7, med7, max7,center_data);
elseif (med9 > min9 && med9 < max9)
    new_pixel = get_center_data(min9, med9, max9,center_data);
else
    new_pixel = center_data;
end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [new_data] = get_center_data(min,med,max,center_data)
if center_data <= min || center_data >= max
    new_data = med;
else
    new_data = center_data;
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% perform median 1d computation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function outbuf = get_median_1d(inbuf)

numpixels = length(inbuf);

tbuf = inbuf;

for ii=coder.unroll(1:numpixels)
    if bitand(ii,uint32(1)) == 1  
        tbuf = compare_stage1(tbuf);
    else
        tbuf = compare_stage2(tbuf);
    end
end

outbuf = tbuf;

end

function outbuf = compare_stage1(inbuf)
numpixels = length(inbuf);
tbuf = compare_stage(inbuf(1:numpixels-1));
outbuf = [tbuf(:)' inbuf(numpixels)];
end

function outbuf = compare_stage2(inbuf)
numpixels = length(inbuf);
tbuf = compare_stage(inbuf(2:numpixels));
outbuf = [inbuf(1) tbuf(:)'];
end

function [outbuf] = compare_stage(inbuf)

step = 2;
numpixels = length(inbuf);

outbuf = inbuf;

for ii=coder.unroll(1:step:numpixels)
    t = compare_pixels([inbuf(ii), inbuf(ii+1)]);
    outbuf(ii) = t(1);
    outbuf(ii+1) = t(2);
end

end

function outbuf = compare_pixels(inbuf)
if (inbuf(1) > inbuf(2))
    outbuf = [inbuf(1), inbuf(2)];
else
    outbuf = [inbuf(2), inbuf(1)];
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% perform median 2d computation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function outbuf = get_median_2d(inbuf)

outbuf = inbuf;
[nrows, ncols] = size(inbuf);
for ii=coder.unroll(1:ncols)
    colData = outbuf(:, ii)';
    colDataOut = get_median_1d(colData)';
    outbuf(:, ii) = colDataOut;
end
for ii=coder.unroll(1:nrows)
    rowData = outbuf(ii, :);
    rowDataOut = get_median_1d(rowData);
    outbuf(ii, :) = rowDataOut;
end

end

Функция MATLAB является модульной и использует несколько функций, чтобы фильтровать шум на изображении.

Адаптивный фильтр MATLAB Испытательного стенда

MATLAB испытательного стенда mlhdlc_median_filter_tb выполняет создание фильтра с помощью репрезентативной входной области значений.

Проверьте испытательный стенд MATLAB:

edit(testbench_name);
I = imread('mlhdlc_img_pattern_noisy.tif');
J = I;

%   Copyright 2011-2019 The MathWorks, Inc.

smax = 9;
[nrows, ncols] = size(I);
ll = ceil(smax/2);
ul = floor(smax/2);

for ii=1:ncols-smax
    for jj=1:nrows-smax
        
        c_idx = ii;                    
        c_data = double(I(jj:jj+smax-1, ii));            
                
        [pixel_val, pixel_valid] = mlhdlc_median_filter(c_data, c_idx);
        
        if pixel_valid
            J(jj, ii) = pixel_val;
        end
    end
end

h = figure;
set( h, 'Name', [ mfilename, '_plot' ] );
subplot( 1, 2, 1 );
imshow( I, [  ] );
subplot( 1, 2, 2 );
imshow( J, [  ] );



Протестируйте алгоритм MATLAB

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

mlhdlc_median_filter_tb

Создайте папку и скопируйте соответствующие файлы

Прежде чем вы сгенерируете HDL-код для проекта MATLAB, скопируйте файлы дизайна и испытательного стенда в папку с возможностью записи. Эти команды копируют файлы во временную папку.

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

Создайте временную папку и скопируйте файлы MATLAB.

cd(tempdir);
[~, ~, ~] = rmdir(mlhdlc_temp_dir, 's');
mkdir(mlhdlc_temp_dir);
cd(mlhdlc_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_pattern_noisy.tif'), mlhdlc_temp_dir);

Ускорение проекта для более быстрой симуляции

Чтобы моделировать испытательный стенд быстрее:

1. Создайте файл MEX с помощью MATLAB Coder™. HDL Workflow Advisor автоматизирует эти шаги при выполнении симуляций проекта с фиксированной точкой.

  codegen -o mlhdlc_median_filter -args {zeros(9,1), 0} mlhdlc_median_filter
  [~, tbn] = fileparts(testbench_name);

2. Моделируйте проект с помощью файла MEX. Когда вы запускаете испытательный стенд, HDL Coder использует файл MEX и запускает симуляцию быстрее.

  mlhdlc_median_filter_tb

3. Очистите файл MEX.

  clear mex;
  rmdir('codegen', 's');
  delete(['mlhdlc_median_filter', '.', mexext]);

Создайте HDL Coder проект

1. Создайте проект HDL Coder:

coder -hdlcoder -new mlhdlc_med_filt_prj

2. Добавьте файл mlhdlc_median_filter.m к проекту в качестве функции MATLAB и mlhdlc_median_filter_tb.m в качестве испытательного стенда MATLAB.

3. Щелкните Типы Autodefine и используйте рекомендуемые типы для входных и выходных входов функции MATLAB mlhdlc_median_filter.

Более полное руководство по созданию и заполнению проектов MATLAB HDL Coder см. в разделе «Начало работы с MATLAB в HDL».

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

  1. Нажмите кнопку Советник по рабочему процессу, чтобы запустить Советник по рабочему процессу.

  2. Щелкните правой кнопкой мыши Генерации HDL-кода задачу и выберите Запуск для выбранной задачи.

Один файл HDL mlhdlc_median_filter_fixpt.vhd генерируется для проекта MATLAB. Чтобы изучить сгенерированный HDL-код для создания фильтра, щелкните гиперссылки в окне Генерации кода Журнала.

Если необходимо сгенерировать HDL- файла для каждой функции в проекте MATLAB, на вкладке Advanced Генерации HDL-кода задачи установите флажок Generate instantiable кода for functions. Смотрите также Сгенерируйте Instantiable Code для функций.

Очистка сгенерированных файлов

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

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