ImageView
QtでOpenCVの画像を表示させるためのWidget.
OpenCVではcv::imshow("imageName", imageData )関数を使って簡単に画像を表示できるようになっています.ただ,UI周りの機能があまり充実していないので,UIを色々と使いたいプログラムを書くとなると別のUIライブラリを使用する必要が出てくると思います.
色々な選択肢が考えられると思いますが,このブログでは,主にQtを使ってUIを作成しています.Qtを使ってUIを作成する場合,cv::imshowで表示されるOpenCVウィンドウではなく,Qt独自のWidgetを使ってOpenCVの画像を表示すると色々なUIと組み合わせることができて便利です.
以下がQtでOpenCVの画像を表示するためのサンプルコードになります.
class ImageView : public QWidget
{
    Q_OBJECT
public:
    //! Constructor.
    ImageView(QWidget* parent = 0);
public slots:
    //! Render OpenCV image on the view.
    void renderCVImage( const cv::Mat& image );
protected:
    //! paintEvent override for rendering OpenCV image.
    void paintEvent(QPaintEvent *event);
private:
    QImage _qImage;
    cv::Mat _image;
};
ImageViewクラスはQWidgetを継承して作成し,paintEvent関数をオーバーライドしてOpenCVの画像を表示できるようカスタマイズします.実際にOpenCVのレンダリングの画像をレンダリングしたいときは,imageView->renderCVImage(image)のようにしてレンダリングできるようにしたいと思います.
以下,実装の関連部分になります.
void ImageView::renderCVImage( const cv::Mat &image )
{
    if (image.empty()) return;
    // Convert OpenCV image to QImage
    _qImage = QOpenCVImage::CVMatToQImage( image );
    _image = image;
    update();
}
void ImageView::paintEvent(QPaintEvent *event)
{
    QPainter painter( this );
    if ( _qImage.width() == 0 || _qImage.height() == 0)
    {
        return;
    }
    // Paint QImage on the view.
    painter.drawImage( QPoint( 0, 0 ), _qImage );
}
renderCVImageの実装では,cv::Mat型のimageをQOpenCVImage::CVMatToQImageでQImageに変換し,update関数を呼ぶことにより,その結果paintEventメソッドが呼んでいます.paintEventの中では,単に_qImageに保持しておいた画像をQPainterを使って描画しているだけです.
以下は,QOpenCVImage::CVMatToQImageの実装.
const QImage QOpenCVImage::CVMatToQImage(const cv::Mat& cvImage)
{
    int dim = cvImage.channels();
    cv::Mat cvImage_8U = CVImage::to8U(cvImage);
    cv::Mat imageData =  cv::Mat(cvImage_8U.size(), CV_8UC3, cv::Scalar::all(0) );
    if (dim==4)
    {
        int from_to[] = { 0,0,  1,1,  2,2 };
        cv::mixChannels( &cvImage_8U, 1, &imageData, 1, from_to, 3 );
        imageData = CVImage::setAlphaRegion( imageData, CVImage::alpha(cvImage_8U));
    }
    if (dim==3)
    {
        imageData = cvImage_8U;
    }
    if (dim==2)
    {
        int from_to[] = { 0,0,  1,1 };
        cv::mixChannels( &cvImage_8U, 1, &imageData, 1, from_to, 2 );
    }
    if(dim == 1) {
        cv::cvtColor(cvImage_8U, imageData, CV_GRAY2BGR);
    }
    QImage qImage( (const unsigned char*) imageData.data, imageData.cols, imageData.rows, imageData.step , QImage::Format_RGB888);
    return qImage.rgbSwapped();
}
基本的には,cv::MatのデータをQImageに変換するだけですが,入力のcv::Matデータの型に応じた調整を行う必要があります.この実装では,CV_32FC3, CV_8UC2のようなcv::Mat型を一度CV_8UC3型に揃えてから変換処理を行っています.cv::MatのデータとQImageではビット配列の順番が違うので,rgbSwappedを呼んでデータを修正しています.
