FC2カウンター FPGAの部屋 VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 1
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 1

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する3(fpga.binファイルの生成)”で、fpga.bin の生成まで行っておいて何なのだが、disp_dmar_axis IP がこのままではまずいことに気がついた。
DisplayPort は接続するディスプレイによって、解像度の設定が違ってしまう。XGA のディスプレイだったらXGA 解像度の画像を出して、HD 解像度だったらHD 解像度の画像をLiveVideo に入力する必要がある。その加工はカメラ画像をDMA Write する側でやっていたのだが、今回のDMA Write はFixstars Tech Blog に書いてあるそのままを使用するので、DMA Read 側でいろいろな解像度の画像にすることにしよう。つまり、disp_dmar_axis IP を作り直そう。

今度のDMA Read IP の名前は、disp_dmar_axis_vga とした。
最初にソースコードを貼っておく。
disp_dmar_axis_vga.h を貼っておく。

// disp_dmar_axis_vga.h
// 2019/07/11 by marsee
//

#ifndef __DISP_DMAR_AXIS_VGA_H__
#define __DISP_DMAR_AXIS_VGA_H__

#include "ap_axi_sdata.h"
#include "hls_video.h"

#define VGA_WIDTH 640
#define VGA_HEIGHT 480

#define SVGA_WIDTH 800
#define SVGA_HEIGHT 600

#define XGA_WIDTH 1024
#define XGA_HEIGHT 768

#define HD_WIDTH 1920
#define HD_HEIGHT 1080

#define RESO_SVGA 0
#define RESO_XGA 1
#define RESO_HD  2

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef ap_axiu<32,1,1,1> AP_AXIU32;
typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


disp_dmar_axis_vga.cpp を貼っておく。

// disp_dmar_axis_vga.cpp
// 2019/07/11 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "disp_dmar_axis_vga.h"

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height);

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame){
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=resolution
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=307200 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb0 offset=slave

    AP_AXIU32 pix;
    int max_width, max_height;

    switch((int)resolution){
        case 0: // SVGA
            max_width = SVGA_WIDTH;
            max_height = SVGA_HEIGHT;
            break;
        case 1: // XGA
            max_width = XGA_WIDTH;
            max_height = XGA_HEIGHT;
            break;
        default: // HD
            max_width = HD_WIDTH;
            max_height = HD_HEIGHT;
            break;
    }

    if (active_frame == (ap_uint<2>)0)
        disp_dmar_fb2(fb2, outs, max_width, max_height);
    else if (active_frame == (ap_uint<2>)1)
        disp_dmar_fb0(fb0, outs, max_width, max_height);
    else
        disp_dmar_fb1(fb1, outs, max_width, max_height);
    return(0);
}

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y0: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X0: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb0[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y1: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X1: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb1[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y2: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X2: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb2[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}


disp_dmar_axis_vga_tb.cpp を貼っておく。

// disp_dmar_axis_tb.cpp
// 2019/02/01 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include "hls_opencv.h"

#include "disp_dmar_axis_vga.h"

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame);

#define NUM_FRAME_BUFFER 3
#define FB_NUMBER 0

int main(){
    using namespace cv;
    ap_uint<2> fb_number = FB_NUMBER;
    ap_uint<32> resolution = RESO_XGA;

    AXI_STREAM outs;
    AP_AXIU32 pix;
    ap_uint<32> *frame_buffer;
    
    // OpenCV で 画像を読み込む
    Mat src = imread("bmp_file0.bmp");

    // 画像をセーブするメモリをアロケート
    if ((frame_buffer =(ap_uint<32> *)malloc(NUM_FRAME_BUFFER * sizeof(ap_int<32>) * (src.cols * src.rows))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }
    
    // Mat フォーマットからフレームバッファに画像をロード
    Mat_<Vec3b> src_vec3b = Mat_<Vec3b>(src);
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        for(int y=0; y<src.rows; y++){
            for(int x=0; x<src.cols; x++){
                Vec3b pixel;
                pixel = src_vec3b(y,x);
                int rgb = ((int)(pixel(2))<<16) + ((int)(pixel(1))<<8) + pixel(0);
                frame_buffer[(src.cols*src.rows)*i + (src.cols*y) + x] = rgb;
            }
        }
    }
    
    disp_dmar_axis_vga((volatile ap_int<32> *)frame_buffer,
        (volatile ap_int<32> *)&frame_buffer[src.cols * src.rows],
        (volatile ap_int<32> *)&frame_buffer[2 * (src.cols * src.rows)],
        outs, resolution, fb_number);
        
    // AXI4 Stream から Mat フォーマットに変換しファイルに書き込み
    int row, col;
    switch(resolution){
        case RESO_SVGA:
            row = SVGA_HEIGHT; col = SVGA_WIDTH;
            break;
        case RESO_XGA:
            row = XGA_HEIGHT; col = XGA_WIDTH;
            break;
        default:
            row = HD_HEIGHT; col = HD_WIDTH;
            break;
    }

    Mat dst(row, col, CV_8UC3);
    Mat_<Vec3b> dst_vec3b = Mat_<Vec3b>(dst);
    for(int y=0; y<dst.rows; y++){
        for(int x=0; x<dst.cols; x++){
            outs >> pix;
            int rgb = pix.data;
            //int rgb = frame_buffer[(src.cols*y) + x];
            Vec3b pixel;
            pixel[0] = (rgb & 0xff); // blue
            pixel[1] = (rgb & 0xff00) >> 8; // green
            pixel[2] = (rgb & 0xff0000) >> 16; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    imwrite("dmar_result.bmp", dst);
    
    free(frame_buffer);
    return(0);
}


bmp_file0.bmp を貼っておく。
disp_dmar_axis_vga_8_190712.png
  1. 2019年07月12日 04:53 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/4581-a6a2b5f3
この記事にトラックバックする(FC2ブログユーザー)