OpenCV ARTRAY SDK - eiichiromomma/CVMLAB GitHub Wiki
(OpenCV) ARTRAY SDK
ARTRAY Camera / Capture Module Software Developer Kitの利用
CMOSカメラのSDKを無理矢理OpenCVと組み合わせて使う。
※SDKが無い場合はDirectShow対応版に変えて貰うとよい
OpenCVのアプリケーションの作成と同様に空のコンソールアプリケーションのプロジェクトを作成する。
プロジェクトを作成したらプロパティを開き、
[全般]-[文字セット]:マルチバイト文字セットを使用する
にする。
Unicodeだとエラーが出る。
CArtCamSdk.cpp、CArtCamSdk.hppをプロジェクトのフォルダにコピーし、ソースとヘッダにそれぞれ既存のファイルとして追加する。
DebugおよびReleaseフォルダにArtCamSdk_*.dllを置く。
- SDKはC++のクラスで記述されている。
- 悉くウィンドウハンドルを引数に使っている
一見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()])
取り込む画像の幅と高さを返してくれる。
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グレーでキャプチャするのを作ってみた。 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;
}
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のソースを参照
ファイル名の文字リテラルの問題らしい。Unicodeなのでよく分からない。
#include <Tchar.h>
をインクルードしておいて、_T()して更にキャストで解決。
アホっぽいが以下のようになった。
if (false == (acSdk->LoadLibrary((LPSTR)_T("ArtCamSdk_Sata")))){
return;
}
.dllの拡張子は不要。[[ARTRAYCamera/使い方)使い方 の方でもUnicodeのオプションのままこれで行けるかも。
overrideのやり方がよく分からなかったが以下のコードで解決
protected:
virtual void WndProc(System::Windows::Forms::Message %m) override{
if (m.Msg == WM_GRAPHPAINT){
//リアルタイムで処理して表示するコード
}
}
これでacSdk->CallBackPreview()でForm1のハンドルを渡せば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()])
public:
IplImage *mainimg;
CArtCamSdk *acSdk;
char *mainimgUp;
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);
}
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);
}
上のをやや変更。 安定して表示出来るようになった
※ライセンスがよく分からないので公開停止中