読者です 読者をやめる 読者になる 読者になる

聞きかじりめも

主にC++やメディア処理技術などに関して気付いたことを書いていきます.ここが俺のメモ帳だ!

cv::Mat画像のサブピクセル画素値を取得

久々にOpenCVのTips

画像処理をしていると,テクセルサンプリングのように浮動小数点座標の画素値を取り出したい場合が時々出てきます.そういう時って普通,整数座標の画素値を使ってバイリニア補間するんですけど,なぜか OpenCVでは「特定の1点のサブピクセル画素を取得する」という処理を標準で用意していません(ちなみにcv::Mat::at<>()メソッドの座標値に浮動小数点数を入れてもコンパイルエラーは起きませんが,実際には暗黙的にintに変換された座標値からサンプルされます).サブピクセル精度でコーナー座標を検出するcv::findCornerSubPix()みたいに画像からサブピクセル座標を割り出す処理はあるんですが,今回やりたいのはその逆なんです.

ただし,サブピクセル精度で画像を切り出す処理ならあり,cv::getRectSubPix()でできます.今回のTipsのアイディアは,これで得たいサブピクセル座標を画像中心として3x3画像で切り取り中央座標値をサンプルする,というものです.意外と気づかない手法だと思うので,書き残すことにしました.

 // グレースケール画像mの要素をサブピクセル座標pから取得する
    // 通常のMat::at()メソッドでは四捨五入された座標から取得されてしまうのでcv::getRectSubPix()を利用する
    // 画像範囲外は境界線と同じとする
    // サポートする型はCV_32F or CV_8U
        double sampleSubPix(cv::Mat m, cv::Point2d p)
    {
        cv::Mat r;
        cv::getRectSubPix(m, cv::Size(3, 3), p, r);
        return (double)r.at<float>(1, 1);
    }

上のコードはグレースケール画像のみ対応ですが,同じ方法でカラー画像もできます.ただし,実はcv::getRectSubPix()CV_8UもしくはCV_32Fにしか対応していない関数なので,要素がdoubleのCV_64F画像はサポートしていません.その場合は仕方ないので一旦castしましょう.