湯LOG

主に自分用のメモ

OpenCV tips

- Mat(C++)とCvMat(C)の変換

// Mat → CvMat 代入で変換.
Mat img1;
CvMat _img1 = img1;
// CvMat → Mat コンストラクタで変換.
CvMat img2;
Mat _img2(img2);

どちらの変換もデータはコピーされず参照する

- Matの初期化

Mat m1(3, 3, CV_32F, Scalar(0));
Mat m2(3, 3, CV_32F, 0);  // これだと0で初期化されない
Mat m2(3, 3, CV_32F, 5);  // 0以外は初期値として使われるがScalar()を使ったほうが良い

Matの初期化にはScalar()を使う

- Matのビット深度(ID)をチェック

std::cout << "depth(ID):" << img.depth() << endl;

//CV_8U -> 0
//CV_8S -> 1
//CV_16U -> 2
//CV_16S -> 3
//CV_32S -> 4
//CV_32F -> 5
//CV_64F -> 6

ビット深度は、1ピクセル内の1チャンネルの値を何ビットで表すかということ
数字はビット数で、Uはunsigned、Sはsigned、Fはfloating pointの意味

- CSVファイルをMatに読み込み(行列数指定)

// --------------------------------------------------------------------------------------
// CSV読み込み
//
// 戻り値(bool) 成功 true 失敗 false
//
bool CsvRead(const char* filename,    // CSVファイルの名前
            Mat &m,                 // データを格納するMat
            const int rows,         // 行数
            const int cols)            // 列数
{
    m.create(rows, cols, CV_64F);

    // CSVファイルを開く
    FILE *fp;
    errno_t err = fopen_s( &fp, filename, "r");
    if ( err != 0 )
    {
        fputs("file open error", stderr);
        return false;
    }

    // CSVデータ読み込み
    char line_buffer[1024];
    for(int row = 0; ( (int)fgets( line_buffer, 1024 - 1, fp ) != EOF ) && row < rows; row++)
    {
        if ( strchr( line_buffer, '\n') != NULL )
        {
            line_buffer[strlen(line_buffer)-1] = '\0';
        }

        char *sep_char_pointer;
        char *data_pointer = line_buffer;
        for ( int col = 0; col < cols; col++ )
        {
            m.at<double>(row, col) = atof( data_pointer );
            sep_char_pointer = strchr( data_pointer, (int)',');
            data_pointer = sep_char_pointer + 1;
        }
    }
    fclose(fp);

    return true;
}

- Pixelにアクセス

Mat img(row, col, CV_8UC3);
Mat_<Vec3b>& imgV = (Mat_<Vec3b>&)img;
b = imgV(y, x)[0];
g = imgV(y, x)[1];
r = imgV(y, x)[2];

- カラー画像をRGB各チャネル画像に分離

Mat imgColor(row, col, CV_8UC3);
vector<Mat> planes;
split(imgColor, planes);

- グレー画像3枚でカラー画像を作成

Mat imgColor;
merge(vector<Mat>(3, imgGray), imgColor);

- 重心の計算

Mat img(100, 100, CV_8U); // 処理画像
Moments m = moments(img, true); // モーメントを計算
int cx = (int)(m.m10/m.m00); // 重心のX座標
int cy = (int)(m.m01/m.m00); // 重心のY座標

0以外の値を持った画素領域の重心

- 画素数のカウント

Mat img(100, 100, CV_8U); // 処理画像
Moments m = moments(img, true); // モーメントを計算
int count = (int)m.m00; // 値を持った画素数

- 輝度ウインドウ処理を施して画面表示

void WindowedShow(const string& windowName,    // 表示するウインドウ名
                const Mat& img,                // 画像データ
                const double windowMin,        // 輝度ウインドウの下限
                const double windowMax)        // 輝度ウインドウの上限
{
    Mat imgShow(img.size(), CV_8U);
    img.convertTo(imgShow, CV_8U, 255.0/(windowMax - windowMin), -windowMin);
    namedWindow(windowName, CV_WINDOW_AUTOSIZE);
    imshow(windowName, imgShow);
}

実数型や16bit整数型のイメージを表示する時に使う
最小値、最大値はcv::minMaxLoc(img, &min, &max)で取得可能

- 画像全体のPixel値をシフトする

cv::Mat img(height, width, CV_8U, (void*)pdata);
int shift = -5;
// img = img + shift とは書けない
cv::add(img, (double)shift, img); // これが正解
// 同時に型の変換も行うconvertTo()も使える
// imgCvrt = img * gain + bias;
img.convertTo(imgCvrt, CV_32F, gain, bias);


随時更新します。