2011/12/01

OpenCVで作るビジョンプログラム(1)

お久しぶりです。

Hibikino-MusashiメインプログラマーShinpukuです。

今年はイランオープンにジャパンオープン、世界大会、秋季大会といろいろあって大変なとても充実した一年でした。

中型リーグの交流会もあり、ロボットのプログラムについて熱心な意見交換が行われていました。このブログを見てプログラムの参考にしているという話も聞き、他のチームの役に立ててもらって僕も嬉しい限りです。

さて、今回は質問の多かったビジョンについてお話ししようと思います。

僕たちのロボットには全方位カメラが搭載されてあり、これから画像を取得します。


カメラはSONY製のDFW-VL500です。ドライバは標準のものではなく、CMUのドライバを使っています。

取得したカメラ画像をビジョンで扱いやすいように加工します。
・BGR→RGB変換
・反転(鏡に映している為)
・カメラの取り付け角度に応じて回転
・240×240にトリミング

コードはこのようになります。

int Camera::getImage(IplImage *image)
{
    const int img_w = image->width, img_h = image->height; 
    const int cam_w = CAMERA_WIDTH, cam_h = CAMERA_HEIGHT;
    const int tmp_w = MAX(cam_w, cam_h), tmp_h = tmp_w;
    // 画像取得
    int camError = theCamera.AcquireImageEx(FALSE, NULL);
    // カメラの接続チェック
    if (camError != CAM_SUCCESS) {
        if (camError == CAM_ERROR_NOT_INITIALIZED) printf("Camera is not initialized.\n");
        printf("Some camera trouble.\n");
        return 0;
    }
    // 作業用イメージ
    IplImage *rawCamera = cvCreateImage(cvSize(cam_w, cam_h), IPL_DEPTH_8U, 3);
    IplImage *tmpCamera = cvCreateImage(cvSize(tmp_w, tmp_h), IPL_DEPTH_8U, 3);
    // 画像取得
    theCamera.getRGB((uchar*)rawCamera->imageData, rawCamera->imageSize);
    cvConvertImage(rawCamera, rawCamera, CV_CVTIMG_SWAP_RB);
    // コピー
    cvZero(tmpCamera);
    cvSetImageROI(tmpCamera, cvRect((tmp_w-cam_w)/2, (tmp_h-cam_h)/2, cam_w, cam_h));
    cvCopy(rawCamera, tmpCamera);
    cvResetImageROI(tmpCamera);
    cvReleaseImage(&rawCamera);
    // 反転(鏡に映しているため)
    cvFlip(tmpCamera, tmpCamera);
    // 回転
    IplImage *clnCamera = cvCloneImage(tmpCamera);
    CvMat *rotation = cvCreateMat(2, 3, CV_32FC1);
    CvPoint2D32f center = cvPoint2D32f(tmp_w/2, tmp_h/2);
    cv2DRotationMatrix(center, offset.angle, 1.0, rotation);
    cvWarpAffine(clnCamera, tmpCamera, rotation);
    cvReleaseMat(&rotation);
    cvReleaseImage(&clnCamera);
    // ROIで切り抜き
    CvRect ROI = cvRect((tmp_w-img_w)/2 + offset.x, (tmp_h-img_h)/2 + offset.y, img_w, img_h);
    if (ROI.x < 0) ROI.x = 0;
    if (ROI.y < 0) ROI.y = 0;
    if (ROI.x > (tmp_w - img_w)) ROI.x = tmp_w - img_w; 
    if (ROI.y > (tmp_h - img_h)) ROI.y = tmp_h - img_h; 
    cvSetImageROI(tmpCamera, ROI);
    cvCopy(tmpCamera, image);
    cvReleaseImage(&tmpCamera);
    return 1;
}

最終的に出力される画像はこのようになります。画像の上下左右はロボットの前後左右と対応しています。
面倒なことをしていますが、こうすることでこの後の処理がとてもわかりやすくなります。

ビジョンではいろいろな処理をしていますが、今回はこの辺で。

0 件のコメント: