1. building project on c6416 dskut27/c6416dsk.pdfc6416 report – uday kiran thummalapalli 1....
TRANSCRIPT
C6416 Report – Uday Kiran Thummalapalli
1. BUILDING PROJECT ON C6416 DSK
Connect the DSK kit to the PC and open the Code Composer Studio. All the project files are located under directory “C:\ti\my projects\”.
1) Click Project >> New… to open a build a new project.
Enter the project name as contrast (user specific) as shown in Fig 1(b).
Figure 1.(a) (b) Creating a project
2) Add the required files such as library files, source files, linker files (.cmd), assembly files (.asm). Click on Project >> Add Files to Project … Locate your files as shown in Fig 2.
1
The required libraries are csl6416.lib (C:\ti\C6000\cgtools\lib), dsk6416bsl.lib (C:\ti\C6000\bios\lib), dsp64x.lib (C:\ti\C6400\dsplib\lib), img64x.lib (C:\ti\C6400\imglib\lib), rts6400.lib (C:\ti\C6000\rts\lib). A linker is always required to allocate the memory and define memory address locations.
Figure 2.(a) (b) Adding files to project
3) Click on Project >> Scan All File Dependencies. This step will locate all the required header files.
2
Figure 3.
4) Configure the Build Options
Figure 4.
5) Follow the below figure for the configurations. As the chip we are using is C6416, select the target version as C64xx. Under the preprocessor section, add the include paths for the imglib, dsplib, libraries as the required header files have to be located. Define the symbols here as CHIP_6416.
3
Figure 5.(a) (b) (c) (d) (e) Steps showing the configurations for a C6416 DSP
6) Build the project. An .out file is created in Debug folder if the compilation is successful with no errors.
4
Figure 6.
7) Locate and Load the .out file.
Figure 7.(a) (b) Loading the .out files
5
8) Run the program by pushing the button as shown in the Fig 8 or use the hot key F5.
Figure 8. Executing the program
6
C6416 Report – Uday Kiran Thummalapalli
2. READING AND VIEWING IMAGE FROM A LINEAR ARRAY (MATRIX)
Load the project named Blurred located in the my projects folder. Build the project with all the libraries, source files and linker files included.
Image.h file initializes the image into a linear array. The intensities can be generated by using MATLAB. The array in_img is the input image.
//Image.h #define X_SIZE 256 #define Y_SIZE 256 #define N_PIXELS X_SIZE*Y_SIZE //define pixels intensities in the input image unsigned char in_img[N_PIXELS] = {137,137,134,136,138,135,135,132, 133,139,130,132,132,127,130,129,131,132,139,139,143,147,151,151,149,149,144,134,119,118,90,80,64,62,61,69,71,73,73,74,78,74,76,79,76,75,78,76,78,78,74,74,79,83,83,88,83,90,93,91,96,94,91,102,98,101,97,97,107,102,100,97,97,96,103,99,99,97,104,104,98,101,102,103,101,101,100,101,103,103,101,100,102,105,101,101,105,103,105,105,105,103,104,103,107,104,102,101,100,101,101,99,99,106,105,100,100,100,97,101,104,102,103,106,100,102,96,105,111,103,99,98,101,99,102,98,98,101,96,105,98,99,98,…………………………………………………………………………………………………………………………………,133,139,130,132,132,127,130,129,131,132,139,139,143,147,151,151,149,149,144,134,119,118,90,80,64,62,61,69,71,73,73,74,78,74,76,79,76,75,78,76,78,78,74,74,79,83,83,88,83,90,93,91,96,94,91,102,98,101,97,97,107,102,100,97,97,96,103,99,99,97,104,104,98,101,102,103,101,101,100,101,103,103,101,100,102,105,101,101,105,103,105,105,105,103,104,103,107,104,102,101,100,101,101,99,99,106,105,100,100,100,97,101,104,102,103,106,100,102,96,105,111,103,99,98};
Blurred.c can take the input image and convolve a mask which can blur the image. H is the convolving mask with weighted blurring intensities of box size 3. A higher order mask can be used by redefining the mask H (NH) and also the arguments for ‘IMG_con_3x3’ function. #include <dsk6416.h> #include <stdio.h> /* printf() */ #include <string.h> /* memset() */ #include <img_corr_3x3.h> #include <csl_timer.h> #include "image.h" /* image\kernel dimensions, example pixel data */ #pragma DATA_ALIGN (in_img, 8); #pragma DATA_SECTION (in_img, "SDRAM");
7
#pragma DATA_ALIGN (out_img, 8); #pragma DATA_SECTION (out_img, "SDRAM"); unsigned char out_img[N_PIXELS]; /* filtered image */ /* filter dimensions and coefficients */ #define NH 3 /* kernel is of size NHxNH (needs to be 3 for this program) */ #define BOUNDARY (NH/2) /* 1st and last BOUNDARY rows/cols in output set to 0 */ #pragma DATA_ALIGN (H, 8) char H[NH*NH] = { 1, 2, 1, /* 1/16 2/16 1/16 */ 2, 4, 2, /* 2/16 4/16 2/16 */ 1, 2, 1, /* 1/16 2/16 1/16 */ }; #define SHIFT 4 /* right-shift by 4 (div by 16) */ #define N_COLS_FILTERED Y_SIZE-2*BOUNDARY /* * Faster than memset(), count must be a multiple of * 8 and greater than or equal to 32 */ void memclear( void * ptr, int count ) { long *lptr = ptr; _nassert((int)lptr%8==0); #pragma MUST_ITERATE (32); for (count>>=3; count>0; count--) *lptr++ = 0; } void filter_image() { unsigned char *p = out_img+BOUNDARY*Y_SIZE; int ii, irow; /* set 1st BOUNDARY rows to zero */ memclear(out_img, BOUNDARY*Y_SIZE); /* filter the interior region of the image matrix */ for (irow=BOUNDARY; irow<X_SIZE-BOUNDARY; ++irow) { /* 1st BOUNDARY cols are zero */ for (ii=0; ii<BOUNDARY; ++ii) *p++ = 0; /* * IMG_conv_3x3 requires 3rd arg to be a multiple of 8, * that's why we pass in Y_SIZE instead of N_COLS_FILTERED * (last few filtered pixels are ignored)
8
*/ IMG_conv_3x3(&in_img[(irow-BOUNDARY)*Y_SIZE], p, Y_SIZE, H, SHIFT); /* last BOUNDARY cols are zero */ p += N_COLS_FILTERED; for (ii=0; ii<BOUNDARY; ++ii) *p++ = 0; } /* last BOUNDARY rows are zero */ memclear(out_img+(X_SIZE-BOUNDARY)*Y_SIZE, BOUNDARY*Y_SIZE); } int main(void) { TIMER_Handle hTimer; unsigned int start, stop, overhead, total = 0, t; /* timing */ const int N = 10; /* how many times to profile */ int ii = 0; DSK6416_init(); /* initialize the DSK board support library */ /* configure timer */ hTimer = TIMER_open(TIMER_DEVANY,0); TIMER_configArgs(hTimer, 0x000002C0, 0xFFFFFFFF, 0x00000000); /* compute overhead of calling the timer. */ start = TIMER_getCount(hTimer); /* called twice to avoid L1D miss. */ start = TIMER_getCount(hTimer); stop = TIMER_getCount(hTimer); overhead = stop - start; for (; ii<N; ++ii) { start = TIMER_getCount(hTimer); /* begin "profile area" */ filter_image(); stop = TIMER_getCount(hTimer); /* end "profile area" */ t = (stop-start-overhead) * 8; total += t; printf("# cycles to filter image: %d\n", t); } printf("avg time is %.2f cycles.\n", (float)total/(float)N); }
9
VIEWING THE IMAGE USING CCS
CCS offers simple ways of viewing the data as a graph, histogram, or even as an image. Below steps illustrate a walkthrough for displaying an image.
1) Click View >> Graph >> Image …
2) Select the RGB color space to select the R,G,B plane. A gray scale image can be viewed if all the planes, i.e., R,G,B planes have same arrays. Enter the address location of the image located or a HEX address where the image data have to be read.
10
3) Select the Lines per Display as #rows in the image and Pixels per Line as #columns in the image. Please Select Image Origin as Top Left, else you have an inverted image.
11
4) Now you can see the image displayed in a new window as shown below. A pointer (crosswire) is provided to view the pixel intensities and the locations.
12
C6416 Report – Uday Kiran Thummalapalli
3. MAKING A CONFIGURATION (.cdb) FILE
Writing a linker (.cmd) file is made much easier using the DSP/BIOS configuration
tool of the CCS Studio. Tutorial below here shows a brief description of configuring a
simple memory mapping, RTDX enabling with buffer sizes.
1. Click File >> New >> DSP/BIOS Configuration…
2. Select C64xx.cdb respectively for the C6416 DSP.
3. Expand the System >> Memory trees to view the memory mapping of the chip.
You can insert a new memory segment by right-clicking on the Memory Section
Manager and select Insert MEM…
13
4. Rename the new memory segment as SDRAM (for eg.). Explore the properties of
the memory by right-clicking on the memory section.
14
This opens up a new dialog box where you can edit the starting address and length of the
memory location on the physical address map. Sample entries are shown in the figure
below. You can customize the mapping as per your choice.
5. Similarly, under the tree of Input/Output, right click on the section RTDX – Real-
Time Data Exchange Settings. You can add an entry for RTDX by selecting the
Properties option.
15
On the safe size, enter the buffer size double than required i.e., if the data is 64K (256 x
256 = 65536) have a buffer size of 128K (65536 x 2 = 131072).
6. As you have added the required data segments, you can now save the cdb file and
add that to the project. Save the .cdb file by navigating through File >> Save As…
Include the file in the project (Project >> Add Files to Project …)
16
C6416 Report – Uday Kiran Thummalapalli
4. IMAGE CONTRAST STRETCHING
Contrast stretching (also called Normalization) attempts to improve an image by
stretching the range of intensity values it contains to make full use of possible values. The
first step is to determine the limits over which image intensity values will be extended.
These lower and upper limits will be called a and b, respectively (for standard 8-bit
grayscale pictures, these limits are usually 0 and 255). Next, the histogram of the original
image is examined to determine the value limits (lower = c, upper = d) in the unmodified
picture. If the original range covers the full possible set of values, straightforward
contrast stretching will achieve nothing, but even then sometimes most of the image data
is contained within a restricted range; this restricted range can be stretched linearly, with
original values which lie outside the range being set to the appropriate limit of the
extended output range. Then for each pixel, the original value r is mapped to output value
s using the function:
The code below shows the logic for image contrast stretching:
#include <limits.h>
MATH_H 1
MGLIB */
IZE*Y_SIZE
l not fit in
#include <stdio.h> D_#define _TI_ENHANCE
#include <math.h> ogram.h> /* I#include <img_hist
image dimensions */ /*
#define X_SIZE 128 #define Y_SIZE 128 #define N_PIXELS X_S signed char in_img[N_PIXELS]; un
Input & output buffer both wil/*
internal chip RAM, this pragma places the output buffer in off-chip RAM */
AM"); #pragma DATA_SECTION (out_img, "SBSR
17
unsigned char out_img[N_PIXELS]; /* image histogram goes here, the pragma
scratch buffer needed by IMGLIB */
id compute_range(unsigned char *pin, int N, centile2,
unsigned short cumsum = 0, /* running tally of the cumulative sum
T1 = round((float)N * percentile1), /* threshold
;
image histogram */
24);
location for 1st (lower bound) percentile in histogram */
location for 2nd (upper bound) percentile in histogram */
id contrast_stretch(unsigned char *pin,
aligns the buffer on a 4-byte boundary which is required by IMGLIB */ #pragma DATA_ALIGN (hist, 4) unsigned short hist[256]; /*unsigned short t_hist[1024]; vo float percentile1, float per unsigned char *pbin1, unsigned char *pbin2) { */ for 1st bin */ T2 = round((float)N * percentile2); /* threshold for 2nd bin */ int ii, jj /* calc /* buffers must be initialized to zero */ memset(t_hist, 0, sizeof(unsigned short)*10 memset(hist, 0, sizeof(unsigned short)*256); IMG_histogram(pin, N, 1, t_hist, hist); /* find for (ii=0; ii<256; ++ii) { cumsum += hist[ii]; if (cumsum >= T1) { *pbin1 = ii; break; } } /* find for (jj=ii+1; jj<256; ++jj) { cumsum += hist[jj]; if (cumsum >= T2) { *pbin2 = jj; break; } } } vo unsigned char *pout, int N) { unsigned char a, b; /* lower & upper bounds for scaling function */ float scale, pixel; int ii;
18
/* estimate dynamic range of the input */ compute_range(pin, N, .05, 0.95, &a, &b); /* apply linear scaling function to input pixels, taking care to handle overflow & underflow */ scale = 255.0/(float)(b-a);
19
ii] - a) * scale );
t main(void)
g, out_img, N_PIXELS);
Load the image via File >> Data >> Load… and input the file Xrays.dat for the
file size 16384. (128 X 128 = 16384). Next, run the program and observe the output.
View the images arrays using the View >> Graph >> Image… utility from the CCS.
Below images shows the result of the operation.
for (ii=0; ii<N_PIXELS; ++ii) { pixel = round( (float)(pin[ /* clamp to 8 bit range */ pout[ii] = (pixel<0.f) ? 0 : ((pixel>255.0) ? 255 : pixel); } } in{ //evm_init(); /* initialize the board */ DSK6416_init(); contrast_stretch(in_im printf("contrast stretch completed"); }
C6416 Report – Uday Kiran Thummalapalli
5. LAPLACE TRANSFORMATION USING IMGLIB LIBRARY
The Laplacian is a 2-D isotropic measure of the 2nd spatial derivative of an
image. The Laplacian of an image highlights regions of rapid intensity change and is
therefore often used for edge detection also referred as zero crossing edge detectors. The
Laplacian is often applied to an image that has first been smoothed with something
approximating a Gaussian smoothing filter in order to reduce its sensitivity to noise, and
hence the two variants will be described together here. The operator normally takes a
single gray level image as input and produces another gray level image as output. A
digital Laplacian mask is convoluted on the image using the convolution function from
the IMGLIB.
,
The file in the Laplace folder, calculates the Laplacian image depending on values of the
box filter H. Below shows Laplace.c
#include <dsk6416.h> printf() */
mage\kernel dimensions, example pixel data */
RAM"); d image */
eeds to be 3 for this
put
#include <stdio.h> /* #include <string.h> /* memset() */ #include <img_corr_3x3.h> #include <csl_timer.h> nclude "image.h" /* i#i
#pragma DATA_ALIGN (in_img, 8); DRAM"); #pragma DATA_SECTION (in_img, "S
ragma DATA_ALIGN (out_img, 8); #p
#pragma DATA_SECTION (out_img, "SDunsigned char out_img[N_PIXELS]; /* filtere filter dimensions and coefficients */ /*
#define NH 3 /* kernel is of size NHxNH (nprogram) */ #define BOUNDARY (NH/2) /* 1st and last BOUNDARY rows/cols in outset to 0 */ #pragma DATA_ALIGN (H, 8)
20
char H[NH*NH] = { 0, 1, 0, /* 0 1 0 */ 1, -4, 1, /* 1 -4 1 */
ine SHIFT 0 /* right-shift by 0 (div by 1) */
ong *lptr = ptr;
nt--)
nsigned char *p = out_img+BOUNDARY*Y_SIZE;
set 1st BOUNDARY rows to zero */
filter the interior region of the image matrix */
* 1st BOUNDARY cols are zero */ = 0;
G_conv_3x3 requires 3rd arg to be a multiple of 8,
D
v_3x3(&in_img[(irow-BOUNDARY)*Y_SIZE],
);
last BOUNDARY cols are zero */
= 0;
last BOUNDARY rows are zero */
t main(void)
0, 1, 0, /* 0 1 0 */ }; #def #define N_COLS_FILTERED Y_SIZE-2*BOUNDARY /* * Faster than memset(), count must be a multiple of * 8 and greater than or equal to 32 */ void memclear( void * ptr, int count ) { l _nassert((int)lptr%8==0); #pragma MUST_ITERATE (32); for (count>>=3; count>0; cou *lptr++ = 0; } void filter_image() { u int ii, irow; /* memclear(out_img, BOUNDARY*Y_SIZE); /* for (irow=BOUNDARY; irow<X_SIZE-BOUNDARY; ++irow) { / for (ii=0; ii<BOUNDARY; ++ii) *p++ /* * IM * that's why we pass in Y_SIZE instead of N_COLS_FILTERE * (last few filtered pixels are ignored) */ IMG_con p,
E, Y_SIZ H, SHIFT /* p += N_COLS_FILTERED;
++ii) *p++ for (ii=0; ii<BOUNDARY; } /* memclear(out_img+(X_SIZE-BOUNDARY)*Y_SIZE, BOUNDARY*Y_SIZE); } in
21
{
22
op, overhead, total = 0, t; /* timing */
6_init(); /* initialize the DSK board support library */
configure timer */ ER_DEVANY,0);
/* compute overhead of calling the timer. */
= TIMER_getCount(hTimer);
nt(hTimer); /* begin "profile area" */
intf("avg time is %.2f cycles.\n", (float)total/(float)N);
View the images arrays using the View >> Graph >> Image… utility from CCS. Below
images shows in_img and out_img.
TIMER_Handle hTimer; unsigned int start, st const int N = 10; /* how many times to profile */ int ii = 0; DSK641 /* hTimer = TIMER_open(TIM TIMER_configArgs(hTimer, 0x000002C0, 0xFFFFFFFF, 0x00000000); start = TIMER_getCount(hTimer); /* called twice to avoid L1D miss. */ start stop = TIMER_getCount(hTimer); overhead = stop - start; for (; ii<N; ++ii) { start = TIMER_getCou filter_image(); stop = TIMER_getCount(hTimer); /* end "profile area" */ t = (stop-start-overhead) * 8; total += t; printf("# cycles to filter image: %d\n", t); } pr}
C6416 Report – Uday Kiran Thummalapalli
6. MEDIAN FILTERING USING A 3 X 3 KERNEL
Image noise is the random variation of brightness or color information in images
produced by the sensor and circuitry of a scanner or digital camera. Image noise can also
originate in film grain and in the unavoidable shot noise of an ideal photon detector. It is
generally regarded as an undesirable by-product of image capture. Salt and pepper noise
is a form of noise typically seen on images. It represents itself as randomly occurring
white and black pixels. An effective noise reduction method for this type of noise
involves the usage of a median filter. It has been reported that modified median filters are
capable of removing speckle noise from the ultrasound images to an extent.
Considering a 3 X 3 kernel in the image matrix, median is the middle value when
all the numbers in the kernel are arranged in ascending order (i.e., 5th pixel, in case of a 3
X 3 kernel). During this process, the random white pixel (salt) or the black pixel (pepper)
are removed as they go the extremities in the ascending or the descending order.
The file median_filter3X3.c performs the above mentioned operation.
#define CHIP_6416 #include <dsk6416.h> #include <stdio.h> /* printf() */ #include <string.h> /* memset() */ #include <img_median_3x3.h> #include <csl_timer.h> #include <csl_dat.h> /* DMA */ //#include "image.h" /* image\kernel dimensions, example pixel data */ #include "tanks2.h" #pragma DATA_ALIGN (in_img, 8); #pragma DATA_SECTION (in_img, "SDRAM"); #pragma DATA_ALIGN (out_img, 8); #pragma DATA_SECTION (out_img, "SDRAM"); unsigned char out_img[N_PIXELS]; /* filtered image */ /* filter dimensions and coefficients */ #define NH 3 /* kernel is of size NHxNH (needs to be 3 for this program) */ #define BOUNDARY 1 /* * For block processing, segment image into individual chunks * that are then paged in and out of internal memory.
23
*/ #define NUM_SCAN_LINES 16 /* # rows constituting a block, must divide evenly into X_SIZE */ #define NUM_BLOCKS (X_SIZE/NUM_SCAN_LINES) /* # blocks in partitioned image */ #define BLOCK_X_SIZE (NUM_SCAN_LINES+2*BOUNDARY) /* how many rows each block is */ /* * These are scratch buffers, strategically placed in on-chip RAM: * * input_buf = input pixels, passed to IMG_median_3x3 * output_buf = filtered pixels */ #pragma DATA_ALIGN (input_buf, 8); unsigned char input_buf[BLOCK_X_SIZE*Y_SIZE]; #pragma DATA_ALIGN (output_buf, 8); unsigned char output_buf[NUM_SCAN_LINES*Y_SIZE]; /* * Faster than memset(), count must be a multiple of * 8 and greater than or equal to 32 */ void memclear( void * ptr, int count ) { long * lptr = ptr; _nassert((int)lptr%8==0); #pragma MUST_ITERATE (32); for (count>>=3; count>0; count--) *lptr++ = 0; } /* Filter one block of an image, returns row index for next block */ int filter_block(int irow, int nrows, const unsigned char *restrict pin, unsigned char *restrict pout) { int jj = irow; for (; jj<irow+nrows; ++jj) { IMG_median_3x3(pin, Y_SIZE, pout); pin += Y_SIZE; /* incr scan-line in preparation for next iteration */ pout += Y_SIZE; } return jj-1; } /* March down the image block-by-block, filtering along the way */ void filter_image() { Uint32 id_EDMAin = DAT_XFRID_WAITNONE, id_EDMAout = DAT_XFRID_WAITNONE; int irow = BOUNDARY; unsigned char *pout_img = out_img, *pin_img = &in_img[(NUM_SCAN_LINES+BOUNDARY)*Y_SIZE], /*
24
* We reuse the bottom-most portion of input_buf * by shifting it to the top, prior to the beginning * of the subsequent block filtering. The 1st time * through the "interior of the image" loop, the * the pointer to bottom-most portion (pinput_buf_row2move_1) * is different from the subsequent iterations * (pinput_buf_row2move_n). */ *pinput_buf_row2move_1 = input_buf + (BLOCK_X_SIZE-3*BOUNDARY)*Y_SIZE, *pinput_buf_row2move_n = input_buf + NUM_SCAN_LINES*Y_SIZE, *pinput_buf_row2move = pinput_buf_row2move_1, *pinput_buf_row2copy_into = input_buf+2*BOUNDARY*Y_SIZE; /************************************************************** * Algorithm 'prologue': filter the 1st block **************************************************************/ id_EDMAin = DAT_copy(in_img, input_buf, (BLOCK_X_SIZE-BOUNDARY)*Y_SIZE); memclear(output_buf, BOUNDARY*Y_SIZE); /* 1st few rows are 0 */ DAT_wait(id_EDMAin); irow = filter_block(irow, NUM_SCAN_LINES, input_buf, output_buf + BOUNDARY*Y_SIZE); /************************************************************** * Filter the interior of the image **************************************************************/ for (; irow<X_SIZE-NUM_SCAN_LINES; ++irow) { /* page out the most recently processed block */ id_EDMAout = DAT_copy(output_buf, pout_img, NUM_SCAN_LINES*Y_SIZE); pout_img += NUM_SCAN_LINES*Y_SIZE; /* page in the next block of pixel data */ /* * 1st shift the scan-lines we can reuse from the bottom * to the top of the scractch buffer. */ memcpy(input_buf, pinput_buf_row2move, 2*BOUNDARY*Y_SIZE); pinput_buf_row2move = pinput_buf_row2move_n; /* DMA in next set of scan-lines */ id_EDMAin = DAT_copy(pin_img, pinput_buf_row2copy_into, NUM_SCAN_LINES*Y_SIZE); pin_img += NUM_SCAN_LINES*Y_SIZE; /* gotta wait now for both xfers to complete before proceeding */ DAT_wait(id_EDMAout); DAT_wait(id_EDMAin);
25
irow = filter_block(irow, NUM_SCAN_LINES, input_buf, output_buf); } /************************************************************** * Algorithm 'epilogue': filter the last block **************************************************************/ /* page out the most recently processed block of image data */ id_EDMAout = DAT_copy(output_buf, pout_img, NUM_SCAN_LINES*Y_SIZE); pout_img += (NUM_SCAN_LINES)*Y_SIZE; /* page in the last block of data */ memcpy(input_buf, pinput_buf_row2move, 2*BOUNDARY*Y_SIZE); /* shift scan-lines */ id_EDMAin = DAT_copy(pin_img, pinput_buf_row2copy_into, (NUM_SCAN_LINES-BOUNDARY)*Y_SIZE); /* gotta wait now for both xfers to complete before proceeding */ DAT_wait(id_EDMAout); DAT_wait(id_EDMAin); filter_block(irow, NUM_SCAN_LINES-BOUNDARY, input_buf, output_buf); /* last few rows are zero */ memclear(output_buf + (NUM_SCAN_LINES-BOUNDARY)*Y_SIZE, BOUNDARY*Y_SIZE); /* we're done, page out this final block of pixel data */ id_EDMAout = DAT_copy(output_buf, pout_img, NUM_SCAN_LINES*Y_SIZE); DAT_wait(id_EDMAout); } int main(void) { TIMER_Handle hTimer; unsigned int start, stop, overhead, total = 0, t; /* timing */ const int N = 10; /* how many times to profile */ int ii = 0; DSK6416_init(); /* initialize the DSK board support library */ /* configure timer */ hTimer = TIMER_open(TIMER_DEVANY,0); TIMER_configArgs(hTimer, 0x000002C0, 0xFFFFFFFF, 0x00000000); /* initialize EDMA (1st arg ignored w/ EDMA) */ DAT_open(DAT_CHAANY, DAT_PRI_HIGH, 0); /* compute overhead of calling the timer. */ start = TIMER_getCount(hTimer); /* called twice to avoid L1D miss. */ start = TIMER_getCount(hTimer); stop = TIMER_getCount(hTimer); overhead = stop - start; for (; ii<N; ++ii) { start = clock(); /* begin "profile area" */ filter_image();
26
stop = clock(); /* end "profile area" */ t = (stop-start-overhead) * 8; total += t; printf("# cycles to filter image: %d\n", t); } printf("avg time is %.2f cycles.\n", (float)total/(float)N); }
Generate the image header file using generate_header_file.m file. View the image
arrays using View >> Graph >> Image… utility from CCS. Below images shows median
filtered images for different outputs.
27
C6416 Report – Uday Kiran Thummalapalli
7. SOBEL EDGE DETECTION USING RTDX
PROTOCOL AND VISUAL STUDIO COM OBJECT
These are the essential steps in designing a RTDX communication setup:
1. Design a module which handles the image processing on the DSP chip.
2. Program a target program which runs on the C6416 chip. This program includes
all the required data, flags, parameters reception from the host. Later, these
parameters are used as arguments for the designed modules. Create a COFF file
(.out) and load on the chip.
3. Design a host program using Visual Studio (or MATLAB) to transmit images,
options for the target console on the chip. Make a GUI with the required
parameters to e passed to the kit using the MFC configuration tool.
TARGET MODULE:
- Files to be included: (Files located on Sobel_RTDX\Target)
Sobel_edge_detect.cdb
Sobel_edge_detect.c
Img64x.lib
sobel_edge_detectcfg.cmd
- Include the imglib include folder path in the Preprocessor option of the compiler.
28
- Build the project.
- Enable the RTDX Module.
- Load the COFF (.out) file and Run it.
29
Code below shows sobel_edge_detect.c
#include <rtdx.h> /* target API */ #include <stdio.h> #include <IMG_sobel.h> #include <IMG_thr_le2min.h> #include "target.h" /* defines TARGET_INITIALIZE() */ #include "image.h" /* dimensions */ RTDX_CreateInputChannel(ichan); /* input image & T come down this pipe */ RTDX_CreateOutputChannel(ochan); /* processed image back through this pipe */ #pragma DATA_SECTION(img_buf1, "SDRAM"); #pragma DATA_ALIGN (img_buf1, 8); unsigned char img_buf1[N_PIXELS]; #pragma DATA_SECTION(img_buf2, "SDRAM"); #pragma DATA_ALIGN (img_buf2, 8); unsigned char img_buf2[N_PIXELS]; void memclear( void * ptr, int count ) { long *lptr = ptr; _nassert((int)lptr%8==0); #pragma MUST_ITERATE (32); for (count>>=3; count>0; count--) *lptr++ = 0; } unsigned char *sobel_edge_detect() { /* * input & output buffers for IMG_thr_le2min may NOT * alias (see IMG_thr_le2min docs), thus operation * cannot be done "in-place". */ int NH=3; /* kernel is of size NHxNH (needs to be 3 for this program) */ int BOUNDARY = (NH/2); /* 1st and last BOUNDARY rows/cols in output set to 0 */ char H[9] = { -1, -2, -1, /* -1 -2 -1 */ 0, 0, 0, /* 0 0 0 */ 1, 2, 1, /* 1 2 1 */ }; int N_COLS_FILTERED = Y_SIZE-2*BOUNDARY, SHIFT = 0; unsigned char *p = img_buf2+BOUNDARY*Y_SIZE; int ii, irow; /* set 1st BOUNDARY rows to zero */
30
memclear(img_buf2, BOUNDARY*Y_SIZE); /* filter the interior region of the image matrix */ for (irow=BOUNDARY; irow<X_SIZE-BOUNDARY; ++irow) { /* 1st BOUNDARY cols are zero */ for (ii=0; ii<BOUNDARY; ++ii) *p++ = 0; /* * IMG_conv_3x3 requires 3rd arg to be a multiple of 8, * that's why we pass in Y_SIZE instead of N_COLS_FILTERED * (last few filtered pixels are ignored) */ IMG_conv_3x3(&img_buf1[(irow-BOUNDARY)*Y_SIZE], p, Y_SIZE, H, SHIFT); /* last BOUNDARY cols are zero */ p += N_COLS_FILTERED; for (ii=0; ii<BOUNDARY; ++ii) *p++ = 0; } /* last BOUNDARY rows are zero */ memclear(img_buf2+(X_SIZE-BOUNDARY)*Y_SIZE, BOUNDARY*Y_SIZE); return img_buf2; } void main() { int status, run_edge_detector, ii; unsigned char *pimg = NULL; TARGET_INITIALIZE(); RTDX_enableOutput(&ochan); /* enable output channel */ RTDX_enableInput(&ichan); /* enable input channel */ printf("Input & Output channels enabled ...\n"); while (1) { /* wait for the host to send us a threshold */ if (sizeof(run_edge_detector) != (status = RTDX_read(&ichan, &run_edge_detector, sizeof(run_edge_detector)))) printf("ERROR: RTDX_read of edge detection flag failed!\n"); else printf("Edge detection = %s\n", (run_edge_detector)?"yes":"no"); /* now we're expecting X_SIZE x Y_SIZE worth of image data */ if (N_PIXELS != (status = RTDX_read(&ichan, img_buf1, N_PIXELS))) { printf("ERROR: RTDX_read of image failed (%d)!\n", status); exit(-1); } printf("Received %dx%d image\n", X_SIZE, Y_SIZE); /* process the image */ pimg = sobel_edge_detect();
31
/* send it back to host */ printf("Sending processed image data back to host ...\n"); for (ii=0; ii<X_SIZE; ++ii) { /* write one row's worth of data */ if (!RTDX_write(&ochan, pimg+ii*Y_SIZE, Y_SIZE)) { printf("ERROR: RTDX_write of row %d failed!\n", ii); exit(-1); } } /* end (for each row) */ printf("Image segmentation completed.\n"); } }
HOST MODULE:
Intel Integrated Performance Primitives (IPP) and Graphics Device Interface (GDI+)
libraries are required to run the following program. The installation files (.exe) are
located in the Sobel_RTDX\Resources folder.
A sample project for the Host application is already constructed for the RTDX transfer.
Please refer to the folder Sobel_RTDX\Host for the Visual Studio project file,
SegmentationHost.vcproj. Add the IPP library include directory to compiler path, IPP
linker library folder path for linker path and additional static library files to the project.
32
Add the Include path for the IPP library ‘include’ files are located.
Add the Include path for the Additional libraries required from the IPP Stublib folder.
33
Add the required static libraries: gdiplus.lib, ipps.lib, ippi.lib
The line in stdafx.h
#import "C:\ti\cc\bin\rtdxint.dll"
imports the RTDX COM object required for the data transfer. The class Image8bpp
handles the image object read by the GUI and has different functions (Ref. Image8bpp
class members).
This code snippet below can communicate with target module:
From Callbcak function of the Segment button:
void CSegmentationDlg::OnSegmentButton() { if (m_apOrigBitmap.get()) { // 1st tell the target to edge detect or just segment theApp.rtdx()->sendInteger( this->m_edgeDetectCheck.GetCheck()?1:0 ); // next send the image to be processed theApp.rtdx()->sendImage(m_apOrigBitmap.get()); // lastly, read the segmented image m_apProcessedBitmap = auto_ptr<Image8bpp>( theApp.rtdx()->readImage() ); m_apProcessedBitmap->binarize();
34
this->OnPaint(); } }
Methods of the RTDX class has the capable to transfer the data to and from the DSP chip.
Run the project and check the folder Sobel_RTDX\Host\Debug\ for the executable file
(SegmentationHost.exe). This application can transer images. Figure below shows the
GUI of the application.
Load the image and hit the Segment button, while the COFF file (.out) file is running on
the CCS with RTDX enabled.
35
C6416 Report – Uday Kiran Thummalapalli
8. REGION GROWING USING RTDX PROTOCOL
This project is capable of making an RTDX transfer with the target chip, process the
image and resend to the host. Region growing is a method to view objects in an image whose
intensities are below a threshold. The remaining pixels are blacked out or whiten out depending
on the criterion. The main goal of segmentation is to partition an image into regions. We have to
achieve the goal by looking for the boundaries between regions based on discontinuities in gray
levels or color properties. The GUI here has a splitter control which can read a threshold value.
Below here are the codes for the target and the host. The user interface and the GUI elements can
be added/ removed/ modified from the ‘RegiongrowHost.rc’.
TARGET:
- Files to be include (Files located on Regiongrow_RTDX_Net/Target)
Regiongrow.cdb Regiongrow.c Img64x.lib Regiongrow.cmd
Code below shows Regiongrow.c
#include <rtdx.h> /* target API */ #include <stdio.h> #include <IMG_sobel.h> #include <IMG_thr_le2min.h> #include "target.h" /* defines TARGET_INITIALIZE() */ #include "image.h" /* dimensions */ RTDX_CreateInputChannel(ichan); /* input image & T come down this pipe */ RTDX_CreateOutputChannel(ochan); /* processed image back through this pipe */ #pragma DATA_SECTION(img_buf1, "SDRAM"); #pragma DATA_ALIGN (img_buf1, 8); unsigned char img_buf1[N_PIXELS]; #pragma DATA_SECTION(img_buf2, "SDRAM"); #pragma DATA_ALIGN (img_buf2, 8);
36
unsigned char img_buf2[N_PIXELS]; void memclear( void * ptr, int count ) { long *lptr = ptr; _nassert((int)lptr%8==0); #pragma MUST_ITERATE (32); for (count>>=3; count>0; count--) *lptr++ = 0; } region_fill(unsigned char fill_percent) { /* * input & output buffers for IMG_thr_le2min may NOT * alias (see IMG_thr_le2min docs), thus operation * cannot be done "in-place". */ IMG_thr_le2min(img_buf1, img_buf2, Y_SIZE, X_SIZE, fill_percent); } void main() { int status, fill_percent, run_edge_detector, ii; //unsigned char *pimg = img_buf2; TARGET_INITIALIZE(); RTDX_enableOutput(&ochan); /* enable output channel */ RTDX_enableInput(&ichan); /* enable input channel */ printf("Input & Output channels enabled ...\n"); while (1) { /* wait for the host to send us a threshold */ if (sizeof(fill_percent) != (status = RTDX_read(&ichan, &fill_percent, sizeof(fill_percent)))) printf("ERROR: RTDX_read of Fill Percent failed!\n"); else printf("Filling Scale = %d\n", fill_percent); /* wait for the host to send us a threshold */ /*if (sizeof(run_edge_detector) != (status = RTDX_read(&ichan, &run_edge_detector, sizeof(run_edge_detector)))) printf("ERROR: RTDX_read of edge detection flag failed!\n"); else printf("Reversing Fill = %s\n", (run_edge_detector)?"yes":"no");*/ /* now we're expecting X_SIZE x Y_SIZE worth of image data */
37
if (N_PIXELS != (status = RTDX_read(&ichan, img_buf1, N_PIXELS))) { printf("ERROR: RTDX_read of image failed (%d)!\n", status); exit(-1); } printf("Received %dx%d image\n", X_SIZE, Y_SIZE); /* process the image */ region_fill((unsigned char)fill_percent); /* send it back to host */ printf("Sending processed image data back to host ...\n"); for (ii=0; ii<X_SIZE; ++ii) { /* write one row's worth of data */ if (!RTDX_write(&ochan, img_buf2+ii*Y_SIZE, Y_SIZE)) { printf("ERROR: RTDX_write of row %d failed!\n", ii); exit(-1); } } /* end (for each row) */ printf("Region Filling completed.\n"); } }
HOST MODULE:
Compose the ‘vcproject’ for RegiongrowHost and compile for the code for no errors.
Code snippet from ‘RegiongrowDlg.c’, written here below, shows the code for which sends the
information through RTDX and receives the image.
void CSegmentationDlg::OnSegmentButton() { if (m_apOrigBitmap.get()) { // Set the min and max for the scale to region fill m_fillpercent.SetRange(0,256); // 1st tell the target the percentage to fill theApp.rtdx()->sendInteger( this->m_fillpercent.GetPos()); // 2nd tell the target the way it has to fill, from black/ white?? //theApp.rtdx()->sendInteger( this->m_edgeDetectCheck.GetCheck()?1:0 ); // next send the image to be processed theApp.rtdx()->sendImage(m_apOrigBitmap.get()); // lastly, read the segmented image
38
m_apProcessedBitmap = auto_ptr<Image8bpp>( theApp.rtdx()->readImage() ); m_apProcessedBitmap->binarize(); this->OnPaint(); } }
The call back function of the button ‘Fill’ reads the value of the splitter element reads the image and sends to the DSP. Upon, reception from the RTDX, it reads back the image and repaints the figure window. Images below show the result for different values of the threshold.
39
40