OpenCV ARTRAY SDK - eiichiromomma/CVMLAB GitHub Wiki

(OpenCV) ARTRAY SDK

ARTRAY Camera / Capture Module Software Developer Kitの利用

CMOSカメラのSDKを無理矢理OpenCVと組み合わせて使う。

※SDKが無い場合はDirectShow対応版に変えて貰うとよい

関連リンク

OpenCVと組み合わせて使う

プロジェクト

OpenCVのアプリケーションの作成と同様に空のコンソールアプリケーションのプロジェクトを作成する。

プロパティ

プロジェクトを作成したらプロパティを開き、

[全般]-[文字セット]:マルチバイト文字セットを使用する

にする。

Unicodeだとエラーが出る。

ファイルの追加

CArtCamSdk.cpp、CArtCamSdk.hppをプロジェクトのフォルダにコピーし、ソースとヘッダにそれぞれ既存のファイルとして追加する。

DebugおよびReleaseフォルダにArtCamSdk_*.dllを置く。

SDKの特徴

  1. SDKはC++のクラスで記述されている。
  2. 悉くウィンドウハンドルを引数に使っている

一見Windows APIをゴテゴテ使わなければならないようだが、実はハンドルにNULLを渡せば問題ない。

一発勝負の静止画キャプチャ

見本表示無しの一発勝負ソフト

まずやること

取り敢えずグローバルにクラスを作っておく。

CArtCamSdk acSdk;

便利なマクロ

サンプルから拝借

const int SUB_SAMPLE[] = { 1, 2, 4, 8 };
#define GetWidth()	(acSdk.Width()  / SUB_SAMPLE[acSdk.GetSubSample()])
#define GetHeight()	(acSdk.Height() / SUB_SAMPLE[acSdk.GetSubSample()])

取り込む画像の幅と高さを返してくれる。

dllのロード、初期化

acSdk.LoadLibrary("置いたDLLのファイル名(.dllも含める)");

で!TRUEか調べ

acSdk.Initialize(NULL);

で初期化する。

カラーモードの設定

acSdk.SetColorMode(チャネルのビット数の和);

詳しくはhppファイルを参照。 これが合ってないとキャプチャでコケる。

キャプチャ

使ったのはモノクロカメラだったのでチャネル数は1だがカラーの場合は3にしてサイズもそれに対応させる必要がある。

image1 = cvCreateImage(cvSize(GetWidth(),GetHeight()),IPL_DEPTH_8U,1);
Size=(GetWidth())*(GetHeight());
g_pImage = (unsigned char *)image1->imageData;
acSdk.SnapShot(g_pImage, Size, 1);

強引だがこれだけでimage1に画像が収まる。 但し、Y軸の扱いが逆なので入れ替える必要がある。

と書いたがSnapShotの第3引数をTRUEにすれば上下反転した。

表示はOpenCVで説明済み。

一応リアルタイム表示してキャプチャ

ウィンドウに表示しつつキャプチャする。

OpenCV/動画像処理プログラム2の初期化部分を上記の内容にして、

//フレーム画像を取得
image=cvQueryFrame(capture);

を acSdk.SnapShot(g_pImage, Size, 1);

に置き換えるだけで良い。

思ったより簡単に取り込めた。

追記

ループの前に

acSdk.Capture();

をしておくと結構速くなった。SnapShotで毎回行なってしまう初期化を省略してくれるらしい。

ちゃんとキャプチャ

SetPreviewWindowで表示するウィンドウを指定するのだが、MDIで子ウィンドウに表示する訳ではないのでNULLにし、表示矩形は適当な値。 勝手にウィンドウが表示されるので邪魔な場合は破壊する。 当然Preview関数でダダ流し表示を実行しても表示されないが裏でキャプチャする下準備は出来る。

ループ中はSnapSHotの代わりにGetImage関数を使用する。 これでかなり高速に画像取得が可能になる。

ループ前の処理

acSdk.Initialize(NULL);
acSdk.SetPreviewWindow(NULL,0,0,0,0);
acSdk.Preview();

プレビューウィンドウの破壊

強引にPreviewウィンドウが開いてしまうので破壊する。リンカのオプションにuser32.libが必要。

HWND awhwnd = FindWindow(NULL,"Active Window");
DestroyWindow(awhwnd);

ループ中の処理

acSdk.GetImage(g_pImage, Size, 1);

終了処理

acSdk.Close();
acSdk.FreeLibrary();

サンプルソース(10bitグレー)

10bitグレーでキャプチャするのを作ってみた。 IPL_DEPTH_16Uに入れるのでcvConvertScaleで64倍している。 ソースは例によって泥縄。ウェイトのかけ方はかなりいい加減。

    #include <cv.h>
    #include <highgui.h>
    #include <stdio.h>
    #include "CArtCamSdk.hpp"
    
    const int SUB_SAMPLE[] = { 1, 2, 4, 8 };
    #define GetWidth()	(acSdk.Width()  / SUB_SAMPLE[acSdk.GetSubSample()])
    #define GetHeight()	(acSdk.Height() / SUB_SAMPLE[acSdk.GetSubSample()])
    CArtCamSdk acSdk;
    
    enum{
      USE_NORMALIZE=1,
      IMG_WIDTH=512,
      IMG_HEIGHT=512,
      IMG_ORG_X=200,
      IMG_ORG_Y=200,
      EXTIME=1585,
      GGAIN=34,
      WAIT_TIME=66  //1/fps * 1000
    };
    
    IplImage *image1;
    void effect(IplImage *image){
      image1 = cvCloneImage(image);
      cvConvertScale(image,image1,64,0);
      cvShowImage("feed window",image1);
    //  cvSaveImage("test.png)",image1);
      cvReleaseImage(&image1);
    }
      
    int main()
    {
      IplImage *image;
      int keyInput;
      acSdk.LoadLibrary("ArtCamSdk_130MI.dll");
      acSdk.Initialize(NULL);
      if(FALSE==acSdk.SetColorMode(16))fprintf(stderr,"ColorMode Failed");
      if(FALSE==acSdk.SetHalfClock(1))fprintf(stderr,"HalfColock Failed");
      if(FALSE==acSdk.SetCaptureWindowEx(GetWidth(),IMG_ORG_X,IMG_WIDTH,GetHeight(),IMG_ORG_Y,IMG_HEIGHT))fprintf(stderr,"WinSize Failed");
      if(FALSE==acSdk.SetSubSample(SUBSAMPLE_1))fprintf(stderr,"SubSample Failed");
      if(FALSE==acSdk.SetWaitTime(0))fprintf(stderr,"WaitTime Failed");
      if(FALSE==acSdk.SetAutoIris(0))fprintf(stderr,"AutoIris Failed");
      if(FALSE==acSdk.SetExposureTime(EXTIME))fprintf(stderr,"ExposureTime Failed");
      if(FALSE==acSdk.SetGlobalGain(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainRed(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainGreen1(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainGreen2(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainBlue(GGAIN))fprintf(stderr,"GlobalGain Failed");
      acSdk.SetPreviewWindow(NULL,0,0,0,0);
      acSdk.Preview();
      HWND awhwnd = FindWindow(NULL,"Active Window");
      //ダイヤログを表示したい場合
    //  acSdk.SetCameraDlg(awhwnd);
    //  acSdk.SetAnalogDlg(awhwnd);
    //  acSdk.SetImageDlg(awhwnd);
      DestroyWindow(awhwnd);
      image = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_16U,1);
    
      long Size=(IMG_WIDTH)*(IMG_HEIGHT)*sizeof(UINT16);
      LPBYTE g_pImage = (LPBYTE)image->imageData;
      
    //  cvNamedWindow("main window",CV_WINDOW_AUTOSIZE);
      cvNamedWindow("feed window",CV_WINDOW_AUTOSIZE);
      
      int64 preTick;
      double pastTime;
      int myWait=0;
      double tickFreq=cvGetTickFrequency();
      preTick=cvGetTickCount();
      for(;;){
        //フレーム画像を取得
        if (FALSE==acSdk.GetImage(g_pImage, Size, 1)){
          return 1;
        }
    //    cvShowImage("main window",image);
        //画像処理はここで行なう
          effect(image);
        
        //カメラのFPSギリギリで回す
        pastTime=(cvGetTickCount()-preTick)/tickFreq/1000.0;
        keyInput=cvWaitKey(pastTime<WAIT_TIME ? WAIT_TIME-(int)pastTime : 1);
        preTick=cvGetTickCount();
        //ESCキーでループを終了
        if((keyInput&255)==27){
          break;
        }
      }
      //後片付け
    //  cvDestroyWindow("main window");
      cvDestroyWindow("feed window");
      acSdk.Close();
      acSdk.FreeLibrary();
      cvReleaseImage(&image);
      return 0;
    }

サンプルソースその2(10bitグレーで高速キャプチャ)

MAX_N_IMAGE枚分のIplImageを起動時に確保し、キャプチャ中はcvCopyImageのみ行なう。 ファイル名はWindowsAPIで時間を取得してmsec単位の時間を示す。 当然終了時にエラい時間がかかるので注意。

    #include <cv.h>
    #include <highgui.h>
    #include <stdio.h>
    #include <windows.h>
    #include "CArtCamSdk.hpp"
    
    const int SUB_SAMPLE[] = { 1, 2, 4, 8 };
    #define GetWidth()  (acSdk.Width()  / SUB_SAMPLE[acSdk.GetSubSample()])
    #define GetHeight()  (acSdk.Height() / SUB_SAMPLE[acSdk.GetSubSample()])
    CArtCamSdk acSdk;
    
    enum{
      USE_NORMALIZE=1,
      IMG_WIDTH=512,
      IMG_HEIGHT=512,
      IMG_ORG_X=200,
      IMG_ORG_Y=200,
      EXTIME=1585,
      GGAIN=34,
      MAX_N_IMAGE=500,
      WAIT_TIME=500  //1/fps * 1000
    };
    
    IplImage **imagep = new IplImage *[MAX_N_IMAGE];
    char **filenamep = new char *[MAX_N_IMAGE];
    long grabCount=0;
    
    void effect(IplImage *image){
      SYSTEMTIME stTime;
      IplImage *image1;
      if (USE_NORMALIZE){
        image1 = cvCloneImage(image);
        cvConvertScale(image,image1,64,0);
        cvShowImage("feed window",image1);
      }
      //キャプチャ タイミングはWAIT_TIMEまかせ
      grabCount++;
      GetLocalTime(&stTime);
      sprintf(*(filenamep+grabCount),"%d%02d%02d%02d%02d%02d%03d.png)",
        stTime.wYear,stTime.wMonth,stTime.wDay,stTime.wHour,stTime.wMinute,stTime.wSecond,stTime.wMilliseconds);
      if(USE_NORMALIZE){
        cvCopyImage(image1,*(imagep+grabCount));
      }else{
        cvCopyImage(image,*(imagep+grabCount));
      }
      if(USE_NORMALIZE){
        cvReleaseImage(&image1);
      }
    }
      
    int main()
    {
      IplImage *image;
      int keyInput;
      acSdk.LoadLibrary("ArtCamSdk_130MI.dll");
      acSdk.Initialize(NULL);
      if(FALSE==acSdk.SetColorMode(16))fprintf(stderr,"ColorMode Failed");
      if(FALSE==acSdk.SetHalfClock(1))fprintf(stderr,"HalfColock Failed");
      if(FALSE==acSdk.SetCaptureWindowEx(GetWidth(),IMG_ORG_X,IMG_WIDTH,GetHeight(),IMG_ORG_Y,IMG_HEIGHT))fprintf(stderr,"WinSize Failed");
      if(FALSE==acSdk.SetSubSample(SUBSAMPLE_1))fprintf(stderr,"SubSample Failed");
      if(FALSE==acSdk.SetWaitTime(0))fprintf(stderr,"WaitTime Failed");
      if(FALSE==acSdk.SetAutoIris(0))fprintf(stderr,"AutoIris Failed");
      if(FALSE==acSdk.SetExposureTime(EXTIME))fprintf(stderr,"ExposureTime Failed");
      if(FALSE==acSdk.SetGlobalGain(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainRed(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainGreen1(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainGreen2(GGAIN))fprintf(stderr,"GlobalGain Failed");
      if(FALSE==acSdk.SetColorGainBlue(GGAIN))fprintf(stderr,"GlobalGain Failed");
      acSdk.SetPreviewWindow(NULL,0,0,0,0);
      acSdk.Preview();
      HWND awhwnd = FindWindow(NULL,"Active Window");
      //ダイヤログを表示したい場合
    //  acSdk.SetCameraDlg(awhwnd);
    //  acSdk.SetAnalogDlg(awhwnd);
    //  acSdk.SetImageDlg(awhwnd);
      DestroyWindow(awhwnd);
      image = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_16U,1);
      for (int i=0; i< MAX_N_IMAGE; i++){
        if(NULL == (*(imagep+i) = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_16U,1))){
          return 1;
        }
        *(filenamep+i) = new char[256];
      }
      long Size=(IMG_WIDTH)*(IMG_HEIGHT)*sizeof(UINT16);
      LPBYTE g_pImage = (LPBYTE)image->imageData;
      
    //  cvNamedWindow("main window",CV_WINDOW_AUTOSIZE);
      cvNamedWindow("feed window",CV_WINDOW_AUTOSIZE);
      
      int64 preTick;
      double pastTime;
      int myWait=0;
      double tickFreq=cvGetTickFrequency();
      preTick=cvGetTickCount();
      acSdk.GetImage(g_pImage, Size, 1);
      while(grabCount < MAX_N_IMAGE){
        //フレーム画像を取得
        if (FALSE==acSdk.GetImage(g_pImage, Size, 1)){
          return 1;
        }
    //    cvShowImage("main window",image);
        //画像処理はここで行なう
        effect(image);
        //WAIT_TIMEで制御
        pastTime=(cvGetTickCount()-preTick)/tickFreq/1000.0;
        keyInput=cvWaitKey(pastTime<WAIT_TIME ? WAIT_TIME-(int)pastTime : 1);
        preTick=cvGetTickCount();
        //ESCキーでループを終了
        if((keyInput&255)==27){
          break;
        }
      }
      //後片付け
    //  cvDestroyWindow("main window");
      if (grabCount){
        for (int i=1; i<=grabCount; i++){
          cvSaveImage(*(filenamep+i),*(imagep+i));
        }
      }
      cvDestroyWindow("feed window");
      acSdk.Close();
      acSdk.FreeLibrary();
      cvReleaseImage(&image);
      return 0;
    }

比較的まっとうな使い方

備忘録なのでざっとメモ書きレベル。

前提

  • ARTCAM-500MI-SATAを利用
  • VC++.Netを利用
  • WM_GRAPHPAINTメッセージを受け取って更新(カメラとの同期)
  • ビルドは/clrオプション
  • 画像の表示はOpenCVの方を参照
  • Form1のメンバとしてクラスへのポインタを置く
  • 初期化はForm1のShownイベント
  • ocuってのはOpenCV/.NET GUIのソースを参照

ハマりポイント

dllが読めない

ファイル名の文字リテラルの問題らしい。Unicodeなのでよく分からない。

#include <Tchar.h>

をインクルードしておいて、_T()して更にキャストで解決。

アホっぽいが以下のようになった。

if (false == (acSdk->LoadLibrary((LPSTR)_T("ArtCamSdk_Sata")))){
  return;
}

.dllの拡張子は不要。[[ARTRAYCamera/使い方)使い方 の方でもUnicodeのオプションのままこれで行けるかも。

WndProcの宣言

overrideのやり方がよく分からなかったが以下のコードで解決

protected:
  virtual void WndProc(System::Windows::Forms::Message %m) override{
    if (m.Msg == WM_GRAPHPAINT){
    //リアルタイムで処理して表示するコード
    }
  }

これでacSdk->CallBackPreview()でForm1のハンドルを渡せばWM_GRAPHPAINTを受け取れる。

WM_GRAPHPAINTを使うと操作ができなくなる

伝送が早過ぎて描画しっぱなしになっているらしい。 TimerをFormに作成して100ごとにイベントを立ててフラグを弄ると良い。

ソースの抜粋

宣言

#include <Tchar.h>
#include "CArtCamSdk.hpp"
const int SUB_SAMPLE[] = { 1, 2, 4, 8 };
#define GetWidth()	(acSdk->Width()  / SUB_SAMPLE[acSdk->GetSubSample()])
#define GetHeight()	(acSdk->Height() / SUB_SAMPLE[acSdk->GetSubSample()])

Form1

インスタンス

public:
  IplImage *mainimg;
  CArtCamSdk *acSdk;
  char *mainimgUp;

Form1_Shown

    private: System::Void Form1_Shown(System::Object^  sender, System::EventArgs^  e) {
            acSdk = new CArtCamSdk();
            if (false == (acSdk->LoadLibrary((LPSTR)_T("ArtCamSdk_Sata")))){
              return;
            }
            //16Uか8Uの2択
            int mainsize = IPL_DEPTH_8U;
            acSdk->Initialize(NULL);
            acSdk->SetCameraType(ARTCAM_CAMERATYPE_SATA_500MI);
            acSdk->SetCaptureWindowEx(2592,0,2592,1944,0,1944);
            if (mainsize == IPL_DEPTH_8U){
              acSdk->SetColorMode(24);
              acSdk->SetWaitTime(100);
            }else{
              acSdk->SetColorMode(48);
              acSdk->SetWaitTime(142);
            }
            acSdk->SetGlobalGain(14);
            acSdk->SetExposureTime(698);

            acSdk->SetBrightness(0);
            acSdk->SetContrast(0);
            acSdk->SetHue(0);
            acSdk->SetSaturation(0);
            acSdk->SetSharpness(0);
            acSdk->SetGamma(100);
            acSdk->SetColorGainBlue(178);
            acSdk->SetColorGainRed(134);
            acSdk->SetBayerMode(2);
            acSdk->SetAutoIris(0);
            //ダイヤログで設定する場合
    //          acSdk->SetCameraDlg(NULL);
    //          acSdk->SetAnalogDlg(NULL);
    //          acSdk->SetImageDlg(NULL);

            LONG Size = GetWidth()*GetHeight()*3*mainsize;
            mainimg = cvCreateImage(cvSize(GetWidth(),GetHeight()),mainsize,3);
            mainimgUp = mainimg->imageData;
            //生画像も表示したいのなら別のピクチャボックスのハンドルをToInt32()して渡せば可能で
            //Active Windowは出てこなくなる。
            acSdk->SetPreviewWindow(NULL,0,0,0,0);
            acSdk->CallBackPreview((HWND)this->Handle.ToInt32(),(LPBYTE)mainimgUp,Size,true);
            //勝手に表示されるActive Windowの消去
            HWND awhwnd = FindWindow(NULL,_T("Active Window"));
            DestroyWindow(awhwnd);
           }

WndProc

    protected:
      virtual void WndProc(System::Windows::Forms::Message %m) override{
        if (m.Msg == WM_GRAPHPAINT){
          IplImage *rg;
          rg = cvCreateImage(cvSize(1024,768),mainimg->depth,3);
          cvResize(mainimg,rg,1);
          if(rg->depth == IPL_DEPTH_16U){
            //中身は10bitらしいので64倍
            cvScale(rg,rg,64.0,0);
          }
          ocu.iplImg = rg;
          if (ocu.iplImg != NULL){
            ocu.RefreshBitmap();
            this->pictureBox1->Image = ocu.bmpImg;
            }
          }        }
          cvReleaseImage(&rg);
        }
        Form::WndProc(m);
      }

サンプルソース

上のをやや変更。 安定して表示出来るようになった

※ライセンスがよく分からないので公開停止中

⚠️ **GitHub.com Fallback** ⚠️