You are on page 1of 38

2D FIR Filter

This example shows how to generate HDL code from a MATLAB design that unsharps an image using 2D FIR filtering. Algorithm The image unsharp technique filters images with a 2D unsharp kernel so the contrast of the image is enhanced. The following MATLAB code shows the effects of unsharping.

image_in = imread('mlhdlc_cameraman.tif' ); H = fspecial('unsharp'); filt_image = imfilter(image_in,H); figure; subplot(1,2,1); imshow(image_in); title('Original'); subplot(1,2,2); imshow(filt_image); title('Sharpened');
MATLAB Design The following example shows how to implement the image processing algorithm for HDL code generation.

design_name = 'mlhdlc_2DFIR.m'; testbench_name = 'mlhdlc_2DFIR_tb.m';


Let us take a look at the MATLAB design

type(design_name); %#codegen function [pixel_out] = mlhdlc_2DFIR(pixel_in) % The 2D FIR algorithm maintains three line buffers. Each iteration the % input pixel is pushed into the current line buffer that is being written to. % The control logic rotates between these three buffers when it reaches the % column boundary. % Each buffer is followed by a shift register and data at the current % column index is pushed into the shift register. % At each iteration a 3x3 kernel of pixels is formed from the pixel input, shift % registers and line buffer outputs. % The kernel is multiplied by a 3x3 filter coefficient mask and the sum of % the resultant values is computed as the pixel output. nRows = 260; nCols = 260; mask = [-0.1667 -0.6667 -0.1667 -0.6667 4.3333 -0.6667 -0.1667 -0.6667 -0.1667]; persistent row_count; persistent col_count; persistent t_minus_1_pixel; persistent t_minus_2_pixel; persistent t_minus_1_memrow1;

persistent t_minus_2_memrow1; persistent t_minus_1_memrow2; persistent t_minus_2_memrow2; persistent t_minus_1_memrow3; persistent t_minus_2_memrow3; persistent mem_row_idx; persistent mem_row1; persistent mem_row2; persistent mem_row3;

if isempty(t_minus_1_memrow3) t_minus_1_memrow3 = 0; t_minus_2_memrow3 = 0; t_minus_1_memrow2 = 0; t_minus_2_memrow2 = 0; t_minus_1_memrow1 = 0; t_minus_2_memrow1 = 0; row_count = 1; col_count = 1; t_minus_1_pixel = 0; t_minus_2_pixel = 0; mem_row_idx = 1; mem_row1 = zeros(1,nCols); mem_row2 = zeros(1,nCols); mem_row3 = zeros(1,nCols); end row_count_r=row_count; col_count_r=col_count; t_minus_1_pixel_r=t_minus_1_pixel; t_minus_2_pixel_r=t_minus_2_pixel; t_minus_1_memrow1_r=t_minus_1_memrow1; t_minus_2_memrow1_r=t_minus_2_memrow1; t_minus_1_memrow2_r=t_minus_1_memrow2; t_minus_2_memrow2_r=t_minus_2_memrow2; t_minus_1_memrow3_r=t_minus_1_memrow3; t_minus_2_memrow3_r=t_minus_2_memrow3; mem_row_idx_r = mem_row_idx;

write_col_idx = col_count_r; current_mem_row1_data = mem_row1(write_col_idx); current_mem_row2_data = mem_row2(write_col_idx); current_mem_row3_data = mem_row3(write_col_idx); if mem_row_idx_r==1 top_row= [t_minus_2_memrow2_r t_minus_1_memrow2_r current_mem_row2_data]; middle_row= [t_minus_2_memrow3_r t_minus_1_memrow3_r current_mem_row3_data]; elseif mem_row_idx_r==2 top_row= [t_minus_2_memrow3_r t_minus_1_memrow3_r current_mem_row3_data]; middle_row= [t_minus_2_memrow1_r t_minus_1_memrow1_r current_mem_row1_data]; else top_row= [t_minus_2_memrow1_r t_minus_1_memrow1_r current_mem_row1_data]; middle_row= [t_minus_2_memrow2_r t_minus_1_memrow2_r current_mem_row2_data]; end bottom_row = [ t_minus_2_pixel_r t_minus_1_pixel_r pixel_in]; kernel = [top_row middle_row bottom_row]; if col_count_r>=3 && row_count_r>=3 %pixel_out=sum(operand.*mask); m1 = kernel(1) * mask(1); m2 = kernel(2) * mask(2); m3 = kernel(3) * mask(3); m4 = kernel(4) * mask(4); m5 = kernel(5) * mask(5); m6 = kernel(6) * mask(6); m7 = kernel(7) * mask(7); m8 = kernel(8) * mask(8); m9 = kernel(9) * mask(9); % tree of adders s1 = m1 + m2; s2 = m3 + m4; s3 = m5 + m6; s4 = m7 + m8; s21 = s1 + s2; s22 = s3 + s4; s31 = s21 + s22; pixel_out = s31 + m9;

else pixel_out=0; end if mem_row_idx_r==1 mem_row1_write_data = pixel_in; mem_row2_write_data = current_mem_row2_data; mem_row3_write_data = current_mem_row3_data; elseif mem_row_idx_r==2 mem_row1_write_data = current_mem_row1_data; mem_row2_write_data = pixel_in; mem_row3_write_data = current_mem_row3_data; else mem_row1_write_data = current_mem_row1_data; mem_row2_write_data = current_mem_row2_data; mem_row3_write_data = pixel_in; end mem_row1(write_col_idx)=mem_row1_write_data; mem_row2(write_col_idx)=mem_row2_write_data; mem_row3(write_col_idx)=mem_row3_write_data; if col_count_r==nCols %toggle memrow if mem_row_idx_r ==1; mem_row_idx=2; elseif mem_row_idx_r ==2; mem_row_idx=3; else mem_row_idx=1; end end t_minus_1_pixel = pixel_in; t_minus_2_pixel = t_minus_1_pixel_r;

t_minus_1_memrow1=current_mem_row1_data; t_minus_2_memrow1=t_minus_1_memrow1_r;

t_minus_1_memrow2=current_mem_row2_data; t_minus_2_memrow2=t_minus_1_memrow2_r;t_minus_1_memrow3=current_mem_row3_data;

t_minus_2_memrow3=t_minus_1_memrow3_r; if col_count_r+1<=nCols col_count = col_count_r+1; else col_count = 1;

if row_count_r<nRows row_count = row_count_r+1; else row_count = 1; end end

end type(testbench_name); clear mlhdlc_2DFIR; TOL = 1e-6; % Read the image image_in = double(imread('mlhdlc_cameraman.tif')); H = fspecial('unsharp');

% Pad the image [rows pixels] = size(image_in); pad_vert_im = [ zeros(1,pixels);zeros(1,pixels);image_in;... zeros(1,pixels);zeros(1,pixels)]; pad_horiz_im = [ zeros(rows+4,2) pad_vert_im zeros(rows+4,2)];

% Reshape the image as a vector [rows pixels] = size(pad_horiz_im); image_vector_length = rows*pixels; image_in_vector = reshape(pad_horiz_im',1,image_vector_length);

% Pre-allocating y for simulation performance y = zeros(1,length(image_in_vector));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Streaming loop calling the design %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

for i = 1:length(image_in_vector)

y(i) = mlhdlc_2DFIR(image_in_vector(i)); end

% Reshape the output back to a 2D matrix image_out = reshape(y,pixels,rows)';

filt_image = imfilter(image_in,H,0); err = filt_image-image_out(4:end-1,4:end-1); err = (err > TOL) .* err;

figure('Name', [mfilename, '_plot']); subplot(1,2,1); imshow(int8(image_out(4:end-1,4:end-1)));title('HDL Output'); subplot(1,2,2); imshow(err);title('Difference');


Create a New HDL Coder Project coder -hdlcoder -new mlhdlc_2dfir_prj Next, add the file 'mlhdlc_2DFIR.m' to the project as the MATLAB Function and 'mlhdlc_2DFIR_tb.m' as the MATLAB Test Bench. You can refer to Getting Started with MATLAB to HDL Workflow tutorial for a more complete tutorial on creating and populating MATLAB HDL Coder projects. Run Fixed-Point Conversion and HDL Code Generation Launch HDL Advisor and right click on the 'Code Generation' step and choose the option 'Run to selected task' to run all the steps from the beginning through the HDL code generation. Examine the generated HDL code by clicking on the hyperlinks in the Code Generation Log window. Enable Distributed Pipelining Option To improve clock frequency of the synthesized circuit you can use the distributed pipelining option to pipeline the multipliers inferred in the design. 1. 2. 3. 4. Choose the option 'Output Pipeline: 10' Enable the option 'Distribute Pipeline Registers' Reset the 'Code Generation' task Rerun the code generation and synthesis steps and examine the synthesis results.

Clean up the Generated Files You can run the following commands to clean up the temporary project folder. mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos'); mlhdlc_temp_dir = [tempdir 'mlhdlc_sobel']; clear mex; cd (mlhdlc_demo_dir); rmdir(mlhdlc_temp_dir, 's');

Corner Detection This example shows how to generate HDL code from design implementing the Harris Stephens Corner Detector in MATLAB. Contents IntroductionSetup for the ExampleSimulate the DesignCreate a New HDL Coder ProjectRun Fixed-Point Conversion and HDL Code GenerationClean up the Generated Files Introduction Corner Detection is used in many Image processing applications like mosaicking, tracking and recognition. Corner detectors are robust to image rotation, translation and variation in lighting The algorithm applies an edge filter to find horizontal and vertical gradients; applies square & gaussian low pass filter on the two gradients. the results are then multiplied and further low pass filtered before computing the corner metric. The testbench takes the corner metric to find the threshold and local maxima to compute corners. The valid pixel information from the design is used to super impose the corners onto the original image design_name = 'mlhdlc_corner_detection.m'; testbench_name = 'mlhdlc_corner_detection_tb.m'; Let us take a look at the MATLAB design type(design_name); %#codegen function [cm] = mlhdlc_corner_detection(data_in) persistent h1 if isempty(h1) h1 = dsp.Delay('FrameBasedProcessing', false); end [xfo, yfo] = sobel_filt(data_in); cm = compute_corner_metric(xfo, yfo); end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function bm = compute_corner_metric(gh, gv) cmh = make_buffer_matrix_gh(gh); cmv = make_buffer_matrix_gv(gv); bm = compute_harris_metric(cmh, cmv); end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function bm = make_buffer_matrix_gh(gh) persistent b1 b2 b3 b4; if isempty(b1) b1 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b2 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b3 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b4 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); end b1p = step(b1, gh); b2p = step(b2, b1p); b3p = step(b3, b2p); b4p = step(b4, b3p); cc = [b4p; b3p; b2p; b1p; gh]; persistent h1 h2 h3 h4; if isempty(h1) h1 = dsp.Delay('FrameBasedProcessing', false);

h2 = dsp.Delay('FrameBasedProcessing', false); h3 = dsp.Delay('FrameBasedProcessing', false); h4 = dsp.Delay('FrameBasedProcessing', false); end h1p = step(h1, cc); h2p = step(h2, h1p); h3p = step(h3, h2p); h4p = step(h4, h3p); bm = [h4p; h3p; h2p; h1p; cc]; end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function bm = make_buffer_matrix_gv(gv) persistent b1 b2 b3 b4; if isempty(b1) b1 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b2 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b3 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); b4 = dsp.Delay('FrameBasedProcessing', false, 'Length', 80); end b1p = step(b1, gv); b2p = step(b2, b1p); b3p = step(b3, b2p); b4p = step(b4, b3p);

cc = [b4p; b3p; b2p; b1p; gv]; persistent h1 h2 h3 h4; if isempty(h1) h1 = dsp.Delay('FrameBasedProcessing', false); h2 = dsp.Delay('FrameBasedProcessing', false); h3 = dsp.Delay('FrameBasedProcessing', false); h4 = dsp.Delay('FrameBasedProcessing', false); end h1p = step(h1, cc); h2p = step(h2, h1p); h3p = step(h3, h2p); h4p = step(h4, h3p); bm = [h4p; h3p; h2p; h1p; cc]; end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function cm = compute_harris_metric(gh, gv) [g1, g2, g3] = gaussian_filter(gh, gv); [s1, s2, s3] = reduce_matrix(g1, g2, g3); cm = (((s1*s3) - (s2*s2)) - (((s1+s3) * (s1+s3)) * 0.04)); end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function [g1, g2, g3] = gaussian_filter(gh, gv)

g=fspecial('gaussian',[5 5],1.5); g1 = (gh .* gh) .* g(:); g2 = (gh .* gv) .* g(:); g3 = (gv .* gv) .* g(:); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function [s1, s2, s3] = reduce_matrix(g1, g2, g3) s1 = sum(g1); s2 = sum(g2); s3 = sum(g3); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% function [xfo, yfo, e] = sobel_filt(u) % Pipelined Sobel Edge Detection algorithm on serialized image. numCols=80; thresh=uint8(157); [xfo, yfo] = s_filter(u, numCols); persistent h1 if isempty(h1) h1 = dsp.Delay('FrameBasedProcessing', false); end ax = abs(xfo); ay = abs(yfo); t = (ax + ay >= thresh);

e = step(h1, t); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% % Compute convolution of serialized image data with sobel masks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% function [xfo, yfo] = s_filter(u, numCols) persistent buf1 buf2; if isempty(buf1) buf1 = dsp.Delay('FrameBasedProcessing', false, 'Length', numCols); buf2 = dsp.Delay('FrameBasedProcessing', false, 'Length', numCols); end lb1 = step(buf1, u); lb2 = step(buf2, lb1); persistent h1 h2 h3 h4 h5 h6; if isempty(h1) h1 = dsp.Delay('FrameBasedProcessing', false); h2 = dsp.Delay('FrameBasedProcessing', false); h3 = dsp.Delay('FrameBasedProcessing', false); h4 = dsp.Delay('FrameBasedProcessing', false); h5 = dsp.Delay('FrameBasedProcessing', false); h6 = dsp.Delay('FrameBasedProcessing', false); end ud1 = step(h1, u); ud2 = step(h2, ud1);

lb1d1 = step(h3, lb1); lb1d2 = step(h4, lb1d1); lb2d1 = step(h5, lb2); lb2d2 = step(h6, lb2d1); xfo = xf(u, ud1, ud2, lb2, lb2d1, lb2d2); yfo = yf(ud2, u, lb1d2, lb1, lb2d2, lb2); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% % Compute x gradient %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% function xf_out = xf(u, xd1, xd2, lb2, zd1, zd2) c2 = 2; t1 = xd1 * c2; a1 = u + t1 + xd2; t1 = zd1 * c2; a2 = lb2 + t1 + zd2; xf_out = a1 - a2; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% % Compute y gradient %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% function yf_out = yf(xd2, u, yd2, lb1, zd2, lb2)

a1 = xd2 - u; t = yd2 - lb1; c2 = 2; a2 = c2 * t; a3 = zd2 - lb2; yf_out = a1 + a2 + a3; end type(testbench_name); clear all; image_in = checkerboard(10); [rows pixels] = size(image_in); image_vector_length = rows*pixels; image_in_vector = reshape(image_in',1,image_vector_length); % Pre-allocating y for simulation performance y = zeros(1,length(image_in_vector)); dataValidOut = y; for i = 1:length(image_in_vector) y(i) = mlhdlc_corner_detection(image_in_vector(i)); end % Reshape output back to 2D array image_out = reshape(y,pixels,rows)'; image_out_crop = image_out(7:end, 7:end); padImage = zeros(size(image_out_crop)+6); padImage(4:end-3,4:end-3) = image_out_crop; findLocalMaxima = vision.LocalMaximaFinder('MaximumNumLocalMaxima', 50, ...

'NeighborhoodSize', [11 11], ... 'Threshold', 0.0005); Corners = step(findLocalMaxima, padImage); drawMarkers = vision.MarkerInserter('Size', 2); % Draw marker circles at corners ImageCornersMarked = step(drawMarkers, image_in, Corners); % Display results figure('Name', 'Corners'); imagesc(image_out), colormap('gray') figure('Name', 'Corners Marked on Original'); imagesc(ImageCornersMarked), colormap('gray') Setup for the Example Executing the following lines of code copies the necessary example files into a temporary folder mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos'); mlhdlc_temp_dir = [tempdir 'mlhdlc_cdetect'];

% 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 the design files to the temporary directory copyfile(fullfile(mlhdlc_demo_dir, design_name), mlhdlc_temp_dir); copyfile(fullfile(mlhdlc_demo_dir, testbench_name), mlhdlc_temp_dir);

Simulate the Design

It is a good practice to simulate the design with the testbench prior to code generation to make sure there are no runtime errors. mlhdlc_corner_detection_tb

Warning: The Computer Vision System Toolbox coordinate system changed. You invoked a function, System object, or block affected by the change. See R2011b Release Notes for details.

Contrast Adjustment

This example shows how to generate HDL code from MATLAB design that adjusts image contrast by linearly scaling pixel values. Contents

IntroductionAlgorithmSimulate the DesignCreate a New Folder and Copy Relevant FilesCreate a New HDL Coder ProjectRun Fixed-Point Conversion and HDL Code GenerationClean up the Generated Files

Introduction

design_name = 'mlhdlc_image_scale.m';

testbench_name = 'mlhdlc_image_scale_tb.m';

Let us take a look at the MATLAB design 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)

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 SF

= 8;

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

NR_OF_BINS MAX_DF

if isempty(offset) offset gain limits_done damping_done = 1; = 1; = 1; = 1;

reset_hist_done scaling_done hist_ind tail_high low_count high_count

= 1; = 1;

= 1; = NR_OF_BINS; = 0; = 0; = 0; = (2^14/DR_PER_BIN) - 1;

min_hist_damped max_hist_damped found_high found_low end if isempty(histogram1) histogram1 histogram2 end = 0; = 0;

= zeros(1, NR_OF_BINS+1); = zeros(1, NR_OF_BINS+1);

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. TODO: Make tail_size_in an input parameter so that we can %chose how many outliers to ignore. Typical value 0.3% %********************************************************************** 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. TODO: Add a %max gain limit, possibly as an input port. This will prevent over %stretching for very low contrast scenes. %********************************************************************** 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)

testFile = 'mlhdlc_img_drive1.tif'; 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']);

subplot(2,2,1); imshow(imgOrig, []); title('Original Image'); subplot(2,2,2); imshow(imgOut, []); title('Scaled Image'); subplot(2,2,3); hist(double(imgOrig(:)),2^14-1); title('Histogram of original Image'); subplot(2,2,4); hist(double(imgOut(:)),2^14-1); title('Histogram of equalized Image'); end

Algorithm The Contrast Adjustment block adjusts the contrast of an image by linearly scaling the pixel values between upper and lower limits. Pixel values that are above or below this range are saturated to the upper or lower limit value, respectively.

Image Enhancement by Histogram Equalization This example shows how to generate HDL code from MATLAB design that does image enhancement using histogram equalization technique. Contents MATLAB DesignAlgorithmSimulate the DesignSetup for the ExampleCreate a New HDL Coder ProjectRun Fixed-Point Conversion and HDL Code GenerationClean up the Generated Files MATLAB Design design_name = 'mlhdlc_heq.m'; testbench_name = 'mlhdlc_heq_tb.m'; Algorithm The Histogram Equalization algorithm enhances the contrast of images by transforming the values in an intensity image so that the histogram of the output image is approximately flat. I = imread('pout.tif'); J = histeq(I); subplot(2,1,1); imhist(I) subplot(2,1,2); imhist(J)

Let us take a look at the MATLAB design

type(design_name);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% % heq.m % Histogram Equalization Algorithm %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% function [x_out y_out pixel_out] = ... mlhdlc_heq(x_in, y_in, pixel_in, width, height)

persistent histogram persistent transferFunc persistent histInd persistent cumSum

if isempty(histogram) histogram = zeros(1, 2^14); transferFunc = zeros(1, 2^14); histInd = 0; cumSum = 0; end

% Figure out indexes based on where we are in the frame if y_in < height && x_in < width % valid pixel data

histInd = pixel_in + 1; elseif y_in == height && x_in == 0 % first column of height+1 histInd = 1; elseif y_in >= height % vertical blanking period histInd = min(histInd + 1, 2^14); elseif y_in < height % horizontal blanking - do nothing histInd = 1; end

%Read histogram (must be outside conditional logic) histValRead = histogram(histInd);

%Read transfer function (must be outside conditional logic) transValRead = transferFunc(histInd);

%If valid part of frame add one to pixel bin and keep transfer func val if y_in < height && x_in < width histValWrite = histValRead + 1; %Add pixel to bin transValWrite = transValRead; %Write back same value cumSum = 0; elseif y_in >= height %In blanking time index through all bins and reset to zero histValWrite = 0; transValWrite = cumSum + histValRead; cumSum = transValWrite; else

histValWrite = histValRead; transValWrite = transValRead; end

%Write histogram (must be outside conditional logic) histogram(histInd) = histValWrite;

%Write transfer function (must be outside conditional logic) transferFunc(histInd) = transValWrite;

pixel_out = transValRead; x_out = x_in; y_out = y_in;

type(testbench_name);

%Test bench for Histogram Equalization

testFile = 'mlhdlc_img_drive1.tif'; 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));

for frame = 1:2 disp(['working on 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_heq(x_in, y_in, pixel_in, width, height);

if x_out < width && y_out < height imgOut(y_out+1,x_out+1) = pixel_out; end end end

figure(1) subplot(2,2,1); imshow(imgOrig, []); title('Original Image'); subplot(2,2,2); imshow(imgOut, []); title('Equalized Image'); subplot(2,2,3); hist(double(imgOrig(:)),2^14-1); title('Histogram of original Image'); subplot(2,2,4); hist(double(imgOut(:)),2^14-1); title('Histogram of equalized Image'); end

Image Format Conversion: RGB to YUV

This example shows how to generate HDL code from MATLAB design implementing a RGB2YUV conversion Contents

MATLAB DesignSetup for the ExampleSimulate the DesignCreate a New HDL Coder ProjectRun FixedPoint Conversion and HDL Code GenerationClean up the Generated Files

MATLAB Design

design_name = 'mlhdlc_rgb2yuv.m'; testbench_name = 'mlhdlc_rgb2yuv_tb.m';

Let us take a look at the MATLAB design type(design_name);

function [x_out y_out y_data_out u_data_out v_data_out] = mlhdlc_rgb2yuv(x_in, y_in, r_in, g_in, b_in) %#codegen

persistent RGB_Reg YUV_Reg persistent x1 x2 y1 y2

if isempty(RGB_Reg) RGB_Reg = zeros(3,1); YUV_Reg = zeros(3,1); x1 = 0; x2 = 0; y1 = 0; y2 = 0; end

D = [.299 .587 .144; -.147 -.289 .436; .615 -.515 -.1]; C = [0; 128; 128];

RGB = [r_in; g_in; b_in];

YUV_1 = D*RGB_Reg; YUV_2 = YUV_1 + C; RGB_Reg = RGB;

y_data_out = round(YUV_Reg(1)); u_data_out = round(YUV_Reg(2)); v_data_out = round(YUV_Reg(3)); YUV_Reg = YUV_2;

x_out = x2; x2 = x1; x1 = x_in; y_out = y2; y2 = y1; y1 = y_in;

type(testbench_name);

FRAMES = 1; WIDTH = 752; HEIGHT = 480; HBLANK = 10;%748; VBLANK = 10;%120;

vidData = double(imread('mlhdlc_img_yuv.tif'));

for f = 1:FRAMES vidOut = zeros(HEIGHT, WIDTH, 3);

for y = 0:HEIGHT+VBLANK-1 for x = 0:WIDTH+HBLANK-1 if y >= 0 && y < HEIGHT && x >= 0 && x < WIDTH b = vidData(y+1,x+1,1); g = vidData(y+1,x+1,2); r = vidData(y+1,x+1,3); else b = 0; g = 0; r = 0; end

[xOut yOut yData uData vData] = ... mlhdlc_rgb2yuv(x, y, r, g, b);

if yOut >= 0 && yOut < HEIGHT && xOut >= 0 && xOut < WIDTH vidOut(yOut+1,xOut+1,:) = [yData vData uData]; end end end

figure(1); subplot(1,2,1); imshow(uint8(vidData)); subplot(1,2,2); imshow(ycbcr2rgb(uint8(vidOut))); drawnow;

end

Setup for the Example

Executing the following lines of code copies the necessary example files into a temporary folder mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');

mlhdlc_temp_dir = [tempdir 'mlhdlc_rgb2yuv'];

% 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), mlhdlc_temp_dir); copyfile(fullfile(mlhdlc_demo_dir, testbench_name), mlhdlc_temp_dir);

Simulate the Design

% It is always a good practice to simulate the design with the testbench prior to % code generation to make sure there are no runtime errors. mlhdlc_rgb2yuv_tb

You might also like