FC2カウンター FPGAの部屋 2010年09月03日
fc2ブログ

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

FPGAの部屋

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

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路22(ソフトでYUV-RGB変換)

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路21(VIO、tcl)”で取得したYUVの値を使って、ソフトウェアでRGBに変換し、BMPフォーマットに直して、パソコンで見てみた。
使った言語はCで、ツールはVisual Studio 2010だった。久しぶりに、しかも新しいバージョンのVisual Studio使ったので戸惑ってしまった。下図のように開発している。
CamDispCntrler_DDR2_40_100903.png

YUV-RGB変換式は下図のものを使用している。

red = (char)((int)(((Y[j]<<8) + V[j]*359 - 45952)>>8)&0xff);
green = (char)(((int)((Y[j]<<8) - V[j]*183 - U[j]*88 + 34688)>>8)&0xff);
blue = (char)((int)(((Y[j]<<8) + U[j]*454 - 58112)>>8)&0xff);


まだスタック関係でバグっているが、取り敢えずBMPファイルが出力できたので良しとする。(どこがバグっているか、わかったら教えてください)
CamDispCntrler_DDR2_41_100903.png

下にCのプログラムを示す。(追記:エラーが出ないように修正しました。武内さん、ありがとうございました

// Camera_Capture.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#pragma warning(disable:4996)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <cstring>

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    char cam_file[100];
    char **cam_red, **cam_green, **cam_blue; // 640*480ピクセル
    BITMAPFILEHEADER bmpfh; // BMPファイルのファイルヘッダ
    BITMAPINFOHEADER bmpih; // BMPファイルのINFOヘッダ
    BMP24FORMAT **bmp_data; // 24ビットのBMPファイルのデータ 640*480
    FILE *fcam, *fbmp;
    int i, j, k;
    char temp_buf[100], temp_buf2[100];
    int U[4], V[4], Y[4];
    char *str;
    unsigned int UVY[8];
    char red, green, blue;

    // 引数の処理
    if (argc == 1) { // 引数なし
        strcpy_s(cam_file, "camera_capture_data.txt");
    } else if (argc == 2){ // 
        strcpy_s(cam_file, (const char *)argv[1]);
    } else {
        fprintf(stderr, "Camera2BMP <camera_capture_data.txt>\n");
        exit(1);
    }

    // メモリをアロケートする
    if ((cam_red =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_redの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    if ((cam_green =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_greenの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    if ((cam_blue =(char **)malloc(sizeof(char *) * 480)) == NULL){
        fprintf(stderr, "cam_blueの1次元目480のメモリを確保できません\n");
        exit(1);
    }
    for (i=0; i<480; i++){
        if ((cam_red[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_redの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    for (i=0; i<480; i++){
        if ((cam_green[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_greenの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    for (i=0; i<480; i++){
        if ((cam_blue[i]=(char *)malloc(sizeof(char) * 640)) == NULL){
            fprintf(stderr, "cam_blueの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*480)) == NULL){
        fprintf(stderr, "bmp_dataの1次元目の480のメモリを確保できません\n");
        exit(1);
    }
    for (i=0; i<480; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * 640)) == NULL){
            fprintf(stderr, "bmp_dataの2次元目の%d番目のメモリが確保できません\n", i);
            exit(1);
        }
    }

    // cam_fileをtext readモードでオープン
    if ((fcam = fopen(cam_file, "rt")) == NULL) {
            fprintf(stderr, "Can't Open %s\n", cam_file);
            exit(1);
    }
    // cam_fileの読み込み
    for (i=0; i<307200; i=i+4){
        if ((k=fscanf(fcam,"%s\n", temp_buf)) == EOF){
            fprintf(stderr, "%s のデータが足りない。%d\n", cam_file, i);
            exit(1);
        } else if (k == 0){
            fprintf(stderr, "%s のデータフォーマットがエラー\n", cam_file);
            exit(1);
        }

        for (str=temp_buf, j=0; j<8; str+=2, j++){
            strncpy(temp_buf2, str, 2); // 2文字コピー
            temp_buf2[2] = '\n';
            sscanf(temp_buf2, "%x\n", &UVY[j]);
        }
        U[0]=UVY[0];
        Y[0]=UVY[1];
        V[0]=UVY[2];
        Y[1]=UVY[3];
        U[2]=UVY[4];
        Y[2]=UVY[5];
        V[2]=UVY[6];
        Y[3]=UVY[7];

        U[1] = U[0]; V[1] = V[0];
        U[3] = U[2]; V[3] = V[2];
        for (j=0; j<4; j++){
            red = (char)((int)(((Y[j]<<8) + V[j]*359 - 45952)>>8)&0xff);
            green = (char)(((int)((Y[j]<<8) - V[j]*183 - U[j]*88 + 34688)>>8)&0xff);
            blue = (char)((int)(((Y[j]<<8) + U[j]*454 - 58112)>>8)&0xff);
            cam_red[(int)(i/640)][(int)((i%640)+j)] = red;
            cam_green[(int)(i/640)][(int)((i%640)+j)]  = green;
            cam_blue[(int)(i/640)][(int)((i%640)+j)] = blue;
        }
    }
    // cam_dataに読み込んだカメラのカラーデータをbmp_dataにをコピー(その際にBMPのデータは左下から始まる)
    for (i=0; i<480; i++){
        for (j=0; j<640; j++){
            bmp_data[479-i][j].red = cam_red[i][j];
            bmp_data[479-i][j].green = cam_green[i][j];
            bmp_data[479-i][j].blue = cam_blue[i][j];
        }
    }
    fclose(fcam);

    // BMPファイルのファイルヘッダに値を代入
    bmpfh.bfType = 0x4d42;
    bmpfh.bfSize = 640*480*3+54;
    bmpfh.bfReserved1 = 0;
    bmpfh.bfReserved2 = 0;
    bmpfh.bfOffBits = 0x36;
    // BMPファイルのINFOヘッダに値を代入
    bmpih.biSize = 0x28;
    bmpih.biWidth = 640;
    bmpih.biHeight = 480;
    bmpih.biPlanes = 0x1;
    bmpih.biBitCount = 24;
    bmpih.biCompression = 0;
    bmpih.biSizeImage = 0;
    bmpih.biXPixPerMeter = 3779;
    bmpih.biYPixPerMeter = 3779;
    bmpih.biClrUsed = 0;
    bmpih.biClrImporant = 0;
    
    // bmpファイルに書き出す
    if ((fbmp=fopen("cam_bmp_file.bmp""wb")) == NULL){
        fprintf(stderr, "cam_bmp_file.bmpがバイナリライトモードで開けません\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfh.bfType, sizeof(char), 2, fbmp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, fbmp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, fbmp);
    // BMPファイルのINFOヘッダの書き込み
    fwrite(&bmpih, sizeof(BITMAPINFOHEADER), 1, fbmp);
    // bmp_dataの書き込み
    for (i=0; i<480; i++) {
        for (j=0; j<640; j++) {
            fputc((int)bmp_data[i][j].blue, fbmp);
            fputc((int)bmp_data[i][j].green, fbmp);
            fputc((int)bmp_data[i][j].red, fbmp);
        }
    }
    fclose(fbmp);
    for(i=0; i<480; i++){
        free(cam_red[i]);
        free(cam_green[i]);
        free(cam_blue[i]);
        free(bmp_data[i]);
    }
    free(cam_red);
    free(cam_green);
    free(cam_blue);
    free(bmp_data);
    
    return 0;
}



BMP用のヘッダは、”BMP ファイルフォーマット”さんから頂いてきたもので、下に示すようなヘッダとなっている。

// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
  unsigned short bfType;
  unsigned long  bfSize;
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned long  bfOffBits;
} BITMAPFILEHEADER;

// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
    unsigned long  biSize;
    long           biWidth;
    long           biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned long  biCompression;
    unsigned long  biSizeImage;
    long           biXPixPerMeter;
    long           biYPixPerMeter;
    unsigned long  biClrUsed;
    unsigned long  biClrImporant;
} BITMAPINFOHEADER;

typedef struct BMP24bitsFORMAT {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
} BMP24FORMAT;


これで、(エラーがまだ出ているが)変換したBMPファイルを下に示す。(大きいので、JPEGに変換してあります)
CamDispCntrler_DDR2_pict_14_100903.jpg

やはり色がおかしいようだ。全体にピンクぽくなっている。
次は、SCCBを接続して、RGB444モードにしてデータを取り込んでみよう。
  1. 2010年09月03日 05:56 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:19