NIOS2隨筆——JPEG解碼與VGA顯示

1. 系統概述

本設計採用NIOS2 32位處理器,通過SPI接口將SD/TF卡中的JPEG圖片數據讀取到內存中,SD/TF卡的文件系統爲FAT32,NIOS2軟件實現JPEG解碼後,啓動framereader和Clocked Video Output模塊,最終在VGA顯示器上顯示JPEG圖像,系統框圖如下:

wKiom1hyOLKh4a8LAABiPj1DLCI656.png


2. JPEG格式

JPEG(Joint Photographic Experts Group)是第一個國際圖像壓縮標準,提供了良好的壓縮性能的同時,具有較好的圖像質量,被廣泛應用電子產品和芯片設計中。

JPEG文件格式有兩種保存方式,分別是Baseline JPEG和Progressive JPEG。

Baseline JPEG:這種類型的JPEG文件存儲方式是按從上到下的掃描方式,把每一行順序的保存在JPEG文件中。顯示時,數據將按照從上到下一行一行的被顯示出來。

Progressive JPEG:包含多次掃描,這些掃描順尋的存儲在JPEG文件中。顯示時,會先顯示整個圖片的模糊輪廓,隨着掃描次數的增加,圖片變得越來越清晰。

JPEG壓縮算法過程如下:

wKiom1hyO-7zQcSTAAAFrvAYuH0466.gif

3. Tiny JPEG Decompressor

TJpgDec是一個通用的JPEG圖像解碼模塊,基於C語言開發且可以用於小型嵌入式系統中。

TJpgDec提供了兩個API函數接口:

  • jd_prepare爲圖像解碼準備足夠的信息

  • jd_decomp執行解碼任務

還提供了兩個I/O函數接口:

  • Input function: 從輸入流中讀取JPEG文件數據

  • Output function: 將圖像數據寫入輸出設備

wKioL1hyPhHRfpzcAAANDOA7iuw621.png

開源的代碼可以在http://elm-chan.org/fsw/tjpgd/00index.html下載。


3. 搭建Qsys

在博文NIOS2隨筆——FAT32文件系統的基礎上,在Qsys平臺上添加framereader和Clocked Video Output組件,設置分辨率爲640*480,VGA相關內容可以參考博文FPGA設計——VGA (Altera)

搭好的Qsys平臺如下圖:

wKioL1hyPzKzq5vPAAEtOwmsJNg487.jpg


4. NIOS2軟件設計

TTJpgDec是基於Baseline JPEG算法編寫,需要以Baseline方式保存一幅JPEG圖片到SD卡中,圖像分辨率爲640*480,文件名爲desk.jpg,在電腦中打開如下:

wKioL1hyP_zCr3ElAAh-zmph3IM660.png

在博文NIOS2隨筆——FAT32文件系統的軟件基礎上,編寫軟件代碼。

移植JPEG軟件解碼模塊,主要是編寫Input和Output函數。VGA顯示部分,要對framereader組件初始化,然後存放在數組中的圖像數據便會不停地被讀取到Clocked Video Output模塊,最後數據會被送到VGA編碼芯片顯示。編寫好的Input、Output及main函數代碼設計如下:

//============JPEG user function==============

/*------------------------------*/
/* User defined input funciton  */
/*------------------------------*/

UINT in_func (JDEC* jd, BYTE* buff, UINT nbyte)
{
    u32  rb=0;	//number of byte read
    f_read(&tf_jpeg,buff,nbyte,&rb);

    return rb;
}

/*------------------------------*/
/* User defined output funciton */
/*------------------------------*/

UINT out_func (JDEC* jd, void* bitmap, JRECT* rect)
{
	   BYTE *src, *dst;
	   UINT y, bws, bwd;

	    if (rect->left == 0) {
	        printf("\r%lu%%", (rect->top << jd->scale) * 100UL / jd->height);
	    }

	    src = (BYTE*)bitmap;
	    dst = picture_buffer + 3 * (rect->top * FRAME_WIDTH+ rect->left);
	    bws = 3 * (rect->right - rect->left + 1);
	    bwd = 3 * FRAME_WIDTH;
	    for (y = rect->top; y <= rect->bottom; y++) {
	        memcpy(dst, src, bws);
	        src += bws; dst += bwd;
	    }

	    return 1;
}

FATFS fs;
FIL  tf_jpeg;
BYTE res=0;

int main (void)
{
	UINT *work;
	JDEC tjpeg_dev;
	UINT x=0;
	UINT y;

	FrameRd_init();

	f_mount(&fs,"",0);
	//Open a JPEG file
	res = f_open(&tf_jpeg,"0:/desk.jpg",FA_READ);

	work = malloc(3800);

	//Prepare to decompress
    res = jd_prepare(&tjpeg_dev, in_func, work, 3800, &tf_jpeg);

	if (res == JDR_OK) {
        //Ready to dcompress. Image info is available here.
        printf("Image dimensions: %u by %u. %u bytes used.\n", tjpeg_dev.width, tjpeg_dev.height, 3800 - tjpeg_dev.sz_pool);

        res = jd_decomp(&tjpeg_dev, out_func, 0);   // Start to decompress with 1/1 scaling
        if (res == JDR_OK) {
            //Decompression succeeded. You have the decompressed image in the frame buffer here.
            printf("\nOK  \n");
        }
        else
        {
            printf("Failed to decompress: rc=%d\n", res);
        }

    }
	else
	{
        printf("Failed to prepare: rc=%d\n", res);
	}

    f_close(&tf_jpeg);       //Close the JPEG file

    for(y=0;y<FRAME_SIZE*3;y=y+3)
    {
    	picture_buf[x] = picture_buffer[y]*65536+(picture_buffer[y+1])*256+(picture_buffer[y+2]);
    	x++;
    }

    printf("image processed done\n");

	while(1);

    return 0;
}


5. 編譯運行

編譯成功後,以Hardware方式運行,終端打印進度信息,最後顯示:image processed done!

wKioL1hyQm7jGpepAAAvyy_w3Nw746.png


6. 最終結果

圖片正常顯示,和電腦上打開的desk.jpg一致,此圖片還是博主4年前用Nokia手機在羣租房裏面拍的一張照片,滿滿的回憶啊。

wKioL1hyRFXzuzPOAAB2FBbvZ1c151.jpg


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章