FC2カウンター FPGAの部屋 Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路22(ソフトでYUV-RGB変換)
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

コメント

 こんにちは。

> 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]);
> }

のsscanfの\nっていりましたっけ? temp_buf2[2] = '\0'; で良いはずですよ。あと、2次元配列のアロケートの仕方ですが、これはチョット・・・。mallocを連続して呼び出しても、必ずしも連接したメモリ・ブロックが得られるわけではありません。一方、配列は連続したメモリ・ブロックの仮定がなされます。
 カメラはOV7670とのことですが、同じ会社のOV9650では、YUV変換用のマトリックスとかガンマとかセットしないと、上手く絵は出なかった記憶があります。
  1. 2010/09/03(金) 10:47:23 |
  2. URL |
  3. くり #-
  4. [ 編集 ]

スタックが壊れるのは自動変数の範囲外に書き込んでいるのだと思います。temp_buf が短かすぎるとか?
  1. 2010/09/03(金) 10:52:13 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

あ、たぶんこっちでしたね。

sscanf(temp_buf2, "%x\n", &UVY[j]);

%x だと unsigned int* を要求しますので、

unsigned int UVY[8];

とする必要がありそうです。
  1. 2010/09/03(金) 10:59:56 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

くりさん、武内さん、こんにちは。

くりさんへ。いつもアドバイスありがとうございます。
>sscanfの\nっていりましたっけ? temp_buf2[2] = '\0'; で良いはずですよ。
はい、そうですね。何でも良いようなので、\nを入れました。入れないと0が帰ってきてしまいますね。
>あと、2次元配列のアロケートの仕方ですが、これはチョット・・・。mallocを連続して呼び出しても、必ずしも連接したメモリ・ブロックが得られるわけではありません。
連接したメモリブロックを得ようと思っているわけではないです。1活でメモリを取るよりも面倒じゃないと思ったので、こう取っています。少し、mallocの管理領域が増えるはずですが、今のパソコンのメモリの搭載量からしたらスズメの涙ほどですよね?(やはり、まずいですか?)

OV7725は、シャープネスだけ切って大丈夫だったので、今度も大丈夫と思ったのですが、調整しないとだめなんでしょうか?
SCCBを付けないとどうしようもないので、付けて設定することにします。

武内さんへ。
>unsigned int UVY[8];
これですね。sscanfがint *だというのは、わかってたはずなんですが、ミスってしまいました。家に帰ったらやってみます。ありがとうございました。
  1. 2010/09/03(金) 13:17:01 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

 こんばんわ。

>%x だと unsigned int* を要求しますので、unsigned int UVY[8];
とする必要がありそうです。

 おオット、所謂一つのバッファ・オーバーフロー攻撃ですね。とすると、この場合、折角読み込んだデータ、書き潰してる可能性が…。

>今のパソコンのメモリの搭載量からしたらスズメの涙ほどですよね?(やはり、まずいですか?)

 これはこれで一つの方法ですが、2次元配列のようで2次元配列でないと言うか、そもそもVGAのサイズ固定であちこちに定数を書き込んでいるので、動的に配列を確保する意味がないんじゃないかと? 単に、

#define MAX_WIDTH (640)
#define MAX_HEIGHT (480)

char cam_red[MAX_HEIGHT][MAX_WIDTH], ・・・

で上手くいきません?
  1. 2010/09/03(金) 21:29:35 |
  2. URL |
  3. くり #-
  4. [ 編集 ]

>この場合、折角読み込んだデータ、書き潰してる可能性が…。

 あ々失礼、x86系などのリトル・エンディアンならば、intの上位バイトはアドレスの上位側に書き込まれますから、この順番なら書き潰している可能性はないですね。
  1. 2010/09/04(土) 00:14:25 |
  2. URL |
  3. くり #-
  4. [ 編集 ]

>あ々失礼、x86系などのリトル・エンディアンならば、intの上位バイトはアドレスの上位側に書き込まれますから、この順番なら書き潰している可能性はないですね。
はい。当然ながらもう一度BMPファイルを作ってみましたが、同じ結果でした。

>char cam_red[MAX_HEIGHT][MAX_WIDTH], ・・・
へっぽこCプログラマーとしては、当然ながら最初にこれをやったのですが、コンパイラに怒られました。エラー内容は詳しく憶えていないですが、領域が大きすぎて取れないじゃなかったかな?
やはり、スタックに領域を確保する自動変数と広大なヒープ領域から領域を確保するmallocの違いだと思います。
ここまで書いて気が付きましたが、くりさんはグローバルに配列を確保しろということですね。こっちは心理的障壁があって、気が付きませんでした。
  1. 2010/09/04(土) 03:57:50 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

VC++のデフォルトスタックサイズは、1MBです。これを超える自動変数を使う場合は、プロパティ->リンカ->システム->スタックサイズでスタックサイズ(バイト数)を設定してやるとよいです。
  1. 2010/09/04(土) 06:17:40 |
  2. URL |
  3. たっく #-
  4. [ 編集 ]

たっくさん、こんにちは。
スタックサイズの設定を確認しました。ありがとうございました。
でも、なるべく、ヒープ領域を使おうと思っています。
  1. 2010/09/04(土) 07:09:53 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

こんにちは。
どうして構造体(or クラス)を使わないんですか?

#define WIDTH 640
#define HEIGHT 480

struct sc_rgb {
unsigned char red[HEIGHT][WIDTH];
unsigned char green[HEIGHT][WIDTH];
unsigned char blue[HEIGHT][WIDTH];
};
と定義しておけば、
struct sc_rgb *rgb_buff;
rgb_buf = (struct sc_rgb *)malloc(sizeof(struct sc_rgb));

で領域が確保でき、以降は

rgb_buf->red[y][x] = hogehoge

な感じで操作できて、簡単だと思うのですが。
  1. 2010/09/04(土) 11:37:00 |
  2. URL |
  3. S #-
  4. [ 編集 ]

Sさん、こんにちは。
お答えします。。。(笑、ふざけてすみません)

それは、最初は白黒用で1つしか値が無かったところに、コピペでRGBに増やしたからです。。。

これは簡単そうですね。今度からこう書こうと思います。ありがとうございました。
  1. 2010/09/04(土) 13:04:22 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

こんにちは。

>スタックに領域を確保する自動変数と広大なヒープ領域から領域を確保するmallocの違いだと思います。

 うーん、昔はスタック領域に制限があったり、大きなサイズの静的な領域を取ると、ファイル・サイズが(当時としては)巨大になったりしたのでmallocで・・、というのがあったと思いますが、今では只の古い因習ですね^^)。このぐらいのサイズだと何処にとっても似たようなものだと思います。ですから、今時のプログラミング作法としては、動的に確保する必要性がある(=実行時までサイズが不明など)場合以外はmallocを使う意味はあまりないかと。Sさんの方法でも、動的確保ではありますが、実行時サイズ可変とはなりません。
 で、折角苦労して2次元配列(もどき)を作った割には、

> cam_red[(int)(i/640)][(int)((i%640)+j)] = red;

とか、何で素直にloop変数2個で回さないんだ?といった、少々、無駄なところで苦労している割合(=バグを作りこむ可能性)が高い気がします。(ちなみにint型に整数演算してもint型のままですのでキャストは必要ないです。)
 やりたいことは、
>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);

の部分ですので、周りはもっとシンプルでもよろしいんじゃないでしょうか?
  1. 2010/09/04(土) 14:41:33 |
  2. URL |
  3. くり #-
  4. [ 編集 ]

>今では只の古い因習ですね
確かにCを覚えたのが古いですから、最初に使えるソフト?を作ったのが、マッキントッシュのAPIを使ったGUIのソフトでした。マックのHTTPサーバー(なんだったか忘れましした?有名なのです)からの情報をもらったCGIソフトでしたね。。。(遠い目。。。)ハンドルを勉強しました。その次はOSF/Motifでしたね。。。

>何で素直にloop変数2個で回さないんだ?
確かに、割り算した時の丸めでどうなるかというのが気になります。(でも大体切り捨てじゃないですか?切り上げるのを御存知ですか?)
これは、2重ループにすべきだったと反省しています。

まあとにかくBMPに変換できれば良いということで。。。

次からは、頂いたアドバイスを考慮してコーディングしようと思います。。。
  1. 2010/09/04(土) 19:36:26 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

くりさん> 今では只の古い因習ですね

どうでしょう。
さすがに 100kb を越えるような自動変数を確保するのは、(今回のような簡単な場合は良いですが)一般論としてはお勧めできない気がします。

marseeさん> まあとにかくBMPに変換できれば良いということで。。。

はい、この用途、この規模のプログラムなら、とりあえず動けばあまり細かいことを気にしなくても、ですね。

ですので以下は完全に蛇足なのですが、こんな書き方もできる、という参考に、
- 可変サイズ配列を含む構造体の確保とアクセス (Windows API などで多用されてます)
- 1つ1つの関数を短くし、それぞれ単一の目的を持たせる
- オブジェクト指向
あたりを考えて書いてみた物です。

コンパイル通してないので、ミスタイプなどはご愛敬、です。

typedef struct tagBITMAPFILE24 {
 struct BITMAPFILEHEADER FileHeader;
 struct BITMAPINFOHEADER InfoHeader;
 struct BMP24FORMAT Pixels[1]; // 本当のサイズは 1 ではない
} BITMAPFILE24;

BITMAPFILE24* BitmapFile24_New(int width, int height)
{
 // Pixels に必要なサイズを含めて確保する
 BITMAPFILE24* result = (BITMAPFILE24*) malloc(
    sizeof(BITMAPFILE24) + sizeof(BMP24FORMAT)*(width*height-1) );
 if (!result) return NULL;

 // ファイルヘッダに値を代入
 result->FileHeader.bfType = 0x4d42;
 result->FileHeader.bfSize = width*height*3+54;
 ...

 // INFOヘッダに値を代入
 ...

 return result;
}

void BitmapFile24_SetPixelRGB(BITMAPFILE24* bf, int x, int y, int r, int g, int b)
{
 int w = bf->InfoHeader.biWidth;
 int h = bf->InfoHeader.biHeight;
 int i = (h-y-1)*w+x; // BMPのデータは左下から始まる

 // C では境界チェックがないので、メモリさえ確保してあれば
 // 定義より大きなインデックスへも正しくアクセスできる
 // バグを生じやすいので ASSERT を入れた方が良いかも
 ASSERT(0<=x && x<w);
 ASSERT(0<=y && y<h);
 ASSERT(0<=i && i<w*h);

 bf->Pixels[i].red = r;
 bf->Pixels[i].green = g;
 bf->Pixels[i].blue = b;
}

void BitmapFile24_SetPixelUVY(BITMAPFILE24* bf, int x, int y, int u, int v, int y)
{
 BitmapFile24_SetPixelRGB(
  bf, x, y,
  ((y<<8) + v*359 - 45952)>>8)&0xff, // r
  ((y<<8) - v*183 - u*88 + 34688)>>8)&0xff, // g
  ((y<<8) + u*454 - 58112)>>8)&0xff // b
 );
}

// 成功したら NULL
// 失敗したらエラーメッセージを返す
const char *BitmapFile24_Save(const BITMAPFILE* bf, const char *file_name)
{
 FILE *fbmp;
 char error_msg[300];
 if ((fbmp=fopen(file_name, "wb")) == NULL){
  snprintf(error_msg, sizeof(error_msg),
   "'%s' をバイナリライトモードで開けません\n", file_name);
  return error_msg;
 }

 // 処理系依存になるけれど、struct 定義で packed を指定できれば
 // fwrite(bf, bf->FileHeader.bfSize, fbmp);
 // だけでいけるかも?
 // http://www.google.co.jp/search?q=struct+packed

 ...

 fclose(fbmp);

 return NULL;
}


int main(int argc, _TCHAR* argv[])
{
 const int w = 640;
 const int h = 480;
 const char *fbmp_name = "cam_bmp_file.bmp";

 ...

 BITMAPFILE24* bf = BitmapFile24_New(w, h);
 ...

  BitmapFile24_SetPixelUVY(bf, x, y, u, v, y);

 ...

 const char *emsg = BitmapFile24_Save(bf, fbmp_name);
 BitmapFile24_Free(bf);
 ...
}

#べらぼうに長い投稿、すみません
  1. 2010/09/05(日) 07:37:28 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

で、色がおかしい件についてですが、本来連続して変化するはずの部分でオーバーフローっぽい不連続な明暗&色調の変化があるところを見ると、変換式、あるいは期待しているデータフォーマットが間違っているように感じられますね。

グレースケール、あるいはカラースケールになるような画像を取り込んで、返還前の生データを数値として目で確認すると、何か分かるかもしれません?
  1. 2010/09/05(日) 08:08:00 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

武内さん、こんにちは。Cコード例ありがとうございました。ASSERT文は知りませんでした。
変換式は、以前使っていたので、問題ないと思うのですが。。。
http://marsee101.blog19.fc2.com/blog-entry-1300.html
http://marsee101.blog19.fc2.com/blog-entry-1318.html

今回、ハードウェアとソフトで変換してた画像は大体感じが同じです。おかしいと思うのはUとVを入れ替えても大して色合いが変わらないことです。
それに上のBMP画像でもわかりますが、最初が黒(値としては00)が続くことです。CMOSカメラのOV7640、OV7725はそんなことはなかったです。OV7670がおかしいのか?この個体がおかしいのか?
とにかく、SCCBの回路を作って(もう出来ているのでつなぐだけ)、RGB444モードにしてやってみたいと思います。
  1. 2010/09/05(日) 09:51:40 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

武内さん、こんにちは。

>グレースケール、あるいはカラースケールになるような画像を取り込んで、返還前の生データを数値として目で確認すると、何か分かるかもしれません?
了解しました。これは良いですね。照明の関係やいろいろな環境の具合で変動するかもしれませんが、目安にはなりそうです。RGBのカラースケールをYUVに変換して、その数値を比較できそうですね。
  1. 2010/09/05(日) 12:42:29 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

 こんにちは。

>さすがに 100kb を越えるような自動変数を確保するのは、(今回のような簡単な場合は良いですが)一般論としてはお勧めできない気がします。

 それは、状況によりますよ。さすがに私も1GByteを要求されればheapからを考えますが^^)。ただ、大きいサイズのメモリはheapから・・・の根拠となる技術的な問題はほぼ解消されてきていますし、一番言いたいことは「鶏を割くに牛刀を用いるな」ってことです。この場合、只のテスト用で、将来、再利用するとしても解像度が変わるだけ、しかも1GByteに達する可能性はまずないのなら、簡単確実で早く仕上がる方法がベストです。

>CMOSカメラのOV7640、OV7725はそんなことはなかったです。

 どうも、ことCMOSカメラの世界では、前のがこうだったからこれも・・・という期待は、裏切られる可能性が高いように感じます。あくまで個人的な感想ですが^^)。
  1. 2010/09/05(日) 14:01:26 |
  2. URL |
  3. くり #-
  4. [ 編集 ]

>簡単確実で早く仕上がる方法がベストです。
そうだとは思います。でも、いろんな方法にチャレンジということも必要なのではないでしょうか?このブログもそのようなコンセプト(のような)で書いています。(気がするだけかもしれませんが。。。)(例を出すと、自分でDDR2 SDRAMコントローラ作らなくても、MIGを使えば済むはずですね。。。)
今回は、簡単な方法を思いつかなかっただけですが、やはり、mallocで取りたいとは思っていました。ですが、簡単に領域を取って作るようにしたいとも思います。(人間は矛盾していますね。)
この辺りは水掛け論的になってきたと思うので、この辺で終わりにしたいと思っています。(もう一度、言うとBMPになれば良いということで。。。)

>期待は、裏切られる可能性が高いように感じます。
そうかもしれません。もしかして、U、Vがunsigned ではなく、signedではないかと思って、変換式を変えてみましたが、だめでした。FPGA-CAFEでSCCBの配線をつないできたので、これで、設定を変えてみます。
ずいぶん長いこと引っ張ってしまいましたが、いろいろな技術を試せているので、良かったかな?と思っています。(OVLやVIOスクリプト駆動)
  1. 2010/09/05(日) 20:28:43 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


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

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