UbuntuでQcam Orbit AFのパン・チルトを使用する(C++用)

Last-modified: 2011-07-09 (土) 15:46:31

目次


today: ?
yesterday: ?
total: ?

更新履歴

2011/07/09

  • プログラム公開

推奨環境

  • OS: Linux(Ubuntu 11.04で確認)
  • OpenCV: 2.3(無くても使える)
  • webcam: svn版(インストール方法はここでは書きません)

このプログラムでできること

  • Qcam Orbit AFのパン・チルト
  • UVC対応カメラのパラメータの変更

ファイル構成

  • main.cpp: 要OpenCV
  • webcam.hpp: これだけなら少し書き換えればOpenCVなしでも可
  • param.yml: 再コンパイルしないでもいくつかのパラメータはここで変更可能

ダウンロード用ファイル

main関数の流れ

/**
 * @file   main.cpp
 * @author Kato Ryuichi <kato@hyrrokkin>
 * @date   Fri Jul  8 11:29:19 2011
 *
 * @brief  Qcam Orbit AFUVC Camera (046d:0994)対応
 * パン・チルト制御プログラム
 *
 */
#include
#include
#include
#include
#include
#include

using namespace std;
using namespace cv;

void capMiss(int capNum, string testImg);
void imgSave(string filePath, vector<Mat> &takeCap);
void help(void){
    cout << "./webcam [-i lena.jpg] [-v video0]" << endl;
}

int main(int argc, char **argv){
    string testImg = "lena.jpg";
    int capNum = -1;
    string videoNum = "video0";
    for(int i = 0; i < argc; i++){
        if(strcmp(argv[i],"-v") == 0){
            videoNum = argv[++i];
	    capNum = (int)videoNum[5] - 48;
	    cout << "Use /dev/video" << capNum << endl;
        }else if(strcmp(argv[i],"-i") == 0)
            testImg = argv[++i];
        else
	    help();
    }
    FileStorage cvfs("param.yml", FileStorage::READ);
    int fc, sh, w, h;
    string list;
    if(cvfs.isOpened()){/// read param.yml
	cvfs["list"] >> list;
	cvfs["focus"] >> fc;
	cvfs["sharpness"] >> sh;
	cvfs["width"] >> w;
	cvfs["height"] >> h;
    }else{
	cout << "[ERROR] YML file not found!" << endl;
	return -1;
    }

    namedWindow("image", CV_WINDOW_AUTOSIZE);
    namedWindow("cap", CV_WINDOW_AUTOSIZE);
    VideoCapture cap(capNum);
    if(!cap.isOpened())
	capMiss(capNum, testImg);
    cap.set(CV_CAP_PROP_FRAME_WIDTH, w);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, h);

    Webcam wc(videoNum);
    wc.devInfo();/// Show device information
    if(list == "ON" || list == "On" || list == "on")
	wc.devCtrlLists();/// Show device control lists
    wc.sharpness(sh, false);
    wc.focus(fc, false);
    int key, i = 0;
    int volume = 800;
    vector<Mat> save;
    while(1){
	stringstream now;
	now << i;
	string fullname;
	if(i < 10)
	    fullname = "capture-0" + now.str() + ".png";
	else
	    fullname = "capture-" + now.str() + ".png";
	Mat frame;
	cap >> frame;
	imshow("cap", frame);
	key = waitKey(10);
	if(key == 'c'){/// image capture
	    imwrite(fullname, frame);
	    i++;
	}
	if(key == 'a')
	    wc.panTilt("pan", -volume);
	if(key == 's')
	    wc.panTilt("PAN", volume);
	if(key == 'w')
	    wc.panTilt("tilt", -volume);
	if(key == 'z')
	    wc.panTilt("Tilt", volume);
	if(key == 'q')
	    break;
    }
    return 0;
}

void capMiss(int capNum, string testImg){
    cout << "Could not find a USB camera!" << endl
	 << "? Device path /dev/video" << capNum << " ?" << endl;
    Mat img = imread(testImg, CV_LOAD_IMAGE_COLOR);
    imshow("image", img);
    waitKey(0);
    exit(0);
}

webcam.hppの流れ

/* $Id: webcam.hpp 2011/07/08 11:49:47 kato Exp $
 * エラー処理と時間計測のためにOpenCV使ってますが,
 * そこだけ書き換えればOpenCVなしでも動きます.
 *
 * Test program for libwebcam.
 * Copyright (c) 2006-2007 Logitech.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef
#define

#include
#include
#include
#include

using namespace std;
using namespace cv;

class Webcam{
private:
    CResult cRet;
    string devName;
    CHandle handle;
public:
    Webcam();
    ~Webcam();
    Webcam(string usbName);
    void initialize(string usbName);
    void devInfo();
    void devCtrlLists();
    void ctrlInfo(CControl *cCtrl);
    int focus(int val, bool check);
    int sharpness(int val, bool check);
    //int panTiltReset(int val);
    int panTilt(string pt, int val);
};

Webcam::Webcam(){}

Webcam::Webcam(string usbName)
    :handle(0)
{
    initialize(usbName);
}

Webcam::~Webcam(){
    cout << devName << " release" << endl;
    c_cleanup();
}

/**
 * webcam.hの初期化
 *
 * @param usbName 使用するカメラ名(ex. "video0")
 */
void Webcam::initialize(string usbName){
    CResult cRet = c_init();
    if(cRet)
	cout << "Unable to c_init (" << cRet << ")" << endl;
    devName = usbName;
}

/**
 * 初期化したカメラの情報を表示する.
 *
 */
void Webcam::devInfo(){
    try{
     	CV_Assert(!handle && !devName.empty());
    }catch(Exception e){
     	exit(0);
    }

    unsigned int size = sizeof(CDevice)
	+ (devName.c_str() ? strlen(devName.c_str()) : 32) + 84;
    CDevice *info = (CDevice *)malloc(size);
    assert(info);

    handle  = c_open_device(devName.c_str());
    int ret = c_get_device_info(handle, devName.c_str(), info, &size);

    if(ret)
	cout << "Failed to c_get_device_info " << ret << endl;
    else
	cout << "-[c_get_device_info(hanlde: " << handle << ")]- -" << endl
	     << " ShortName = " << info->shortName   << ","  << endl
	     << " Name      = " << info->name        << ","  << endl
	     << " Driver    = " << info->driver      << ","  << endl
	     << " Location  = " << info->location    << ","  << endl
	     << "  (vid, pid, bcd) = ("
	     << info->usb.vendor  << ", "
	     << info->usb.product << ", "
	     << info->usb.release  << ")" << endl
	     << "- - - - - - - - - - - - - - - - - -" << endl;
    free(info);
}

/**
 * 初期化したカメラでコントロールできるパラメータの情報を表示する.
 *
 */
inline void Webcam::devCtrlLists(){
    unsigned int size = 0, count = 0;

    cout << "Getting control information for handle " << handle << endl;
    CResult ret = c_enum_controls(handle, NULL, &size, &count);
    if(ret == C_BUFFER_TOO_SMALL){
	CControl *cCtrls = (CControl *)malloc(size);
	ret = c_enum_controls(handle, cCtrls, &size, &count);
	if(ret)
	    cout << "Unable to c_enum_controls (" << ret << ")" << endl;
	for(int i = 0; i < (int)count; i++) {
	    CControl *cCtrl = &cCtrls[i];
	    ctrlInfo(cCtrl);
	}
	free(cCtrls);
    }else
	cout << "No controls found (ret = " << ret << ")" << endl;
}

/**
 * パラメータを呼び出す
 *
 * @param cCtrl パラメータリスト
 */
inline void Webcam::ctrlInfo(CControl *cCtrl){
    cout << cCtrl->name  << " (id:" << cCtrl->id << ")" << endl
	 << "  [type: "  << cCtrl->type  << ","
	 << "  flags: "  << cCtrl->flags << ",";
    if(cCtrl->type == CC_TYPE_CHOICE){
	cout << " choice = {";
	for(int i = 0; i < (int)cCtrl->choices.count; i++){
	    cout << " '" << cCtrl->choices.list[i].name << "'"
		 << "["  << cCtrl->choices.list[i].index << "]";
	}
	cout << " }";
    }else{
	cout << "  min: " << cCtrl->min.value
	     << ", max: " << cCtrl->max.value
	     << ", def: " << cCtrl->def.value
	     << ", step: " << cCtrl->step.value;
    }
    cout << "]" << endl;
}

/**
 * 焦点距離を変更する
 *
 * @param val 変更する値(devCtrlLists()で表示範囲内で)
 * @param check いくつに変更したか表示する(デバック用?)
 *
 * @return 正しく変更できたら0を返す
 */
inline int Webcam::focus(int val, bool check){
    try{
     	CV_Assert(0 <= val && val <= 255);
    }catch(Exception e){
	cout << "  val: " << val << " (0 < val < 255)" << endl;
	return -1;
    }
    CControlValue value;
    value.value = val;
    CResult ret = c_set_control(handle, (CControlId)0x2048D04, &value);
    if(ret){
	cout << "int Webcam::focus(int val, bool check)" << endl
	     << "  (handle: " << handle << ", ret: " << ret
	     << ", val: " << val <<  ")" << endl;
	return 0;
    }else if(check)
	cout << "handle" << handle << " Focus: " << val << endl;
    return -1;
}

/**
 * シャープネスの値を変更する
 *
 * @param val 変更する値(devCtrlLists()で表示範囲内で)
 * @param check いくつに変更したか表示する(デバック用?)
 *
 * @return 正しく変更できたら0を返す
 */
inline int Webcam::sharpness(int val, bool check){
    try{
     	CV_Assert(0 <= val && val <= 255);
    }catch(Exception e){
	cout << "  val: " << val << " (0 < val < 255)" << endl;
	return -1;
    }
    CControlValue value;
    value.value = val;
    CResult ret = c_set_control(handle, CC_SHARPNESS, &value);
    if(ret){
	cout << "int Webcam::sharpness(int val, bool check)" << endl
	     << "  (handle: " << handle << ", ret: " << ret
	     << ", val: " << val <<  ")" << endl;
	return 0;
    }else if(check)
	cout << "handle" << handle << " Sharpness: " << val << endl;
    return -1;
}

/*/
  inline int Webcam::panTiltReset(int val){
  if(val < 0 || 3 < val){
  cout << "int Webcam::sharpness(int val, bool check)" << endl
  << "  val: " << val << " (0 < val < 3)" << endl;
  return -1;
  }
  CControlValue value;
  value.value = val;
  CResult ret = c_set_control(handle, CC_LOGITECH_PANTILT_RESET, &value);
  if(ret)
  cout << "int Webcam::panTiltReset(int val)" << endl
  << "  (handle: " << handle << ", ret: " << ret << ")" << endl;
  else
  cout << "handle" << handle << " PanTilt Reset: " << val << endl;
  return 0;
  }
//*/

/**
 * パン・チルトを制御する
 *
 * @param pt パン・チルトの選択("Pan" or "Tilt")
 * @param val 移動する値
 *
 * @return 正しく変更できたら0を返す
 */
inline int Webcam::panTilt(string pt, int val){
    try{
     	CV_Assert(-1000 <= val && val <= 1000);
    }catch(Exception e){
	cout << "  val: " << val << " (-1000 < val < 1000)" << endl;
	return -1;
    }
    CControlValue value;
    int num = 4;
    value.value = val / num;
    CResult ret = {0};
    for(int i = 0; i < num; i++){
	if(pt == "Pan" || pt == "pan" || pt == "PAN")
	    ret = c_set_control(handle, CC_PAN_RELATIVE, &value);
	if(pt == "Tilt" || pt == "tilt" || pt == "TILT")
	    ret = c_set_control(handle, CC_TILT_RELATIVE, &value);
	waitKey(25);
	if(ret && !i)
	    cout << "void Webcam::panTilt(CHandle handle, int val)" << endl
		 << "  (handle: " << handle
		 << ", ret: " << ret << ")" << endl;
    }
    return 0;
}
#endif