Cocos2d-xでOpenCVを使ってみたかったけど.....


今回は、OpenCVをcocos2d-xで使おうと思ったけどダメだったというお話です。
前回に続き、cocos2d-xを触っていたのですが、動画再生用のノードがcocos2d-xってないみたいですね。

そこで、私の得意分野なOpenCVを使って動画ファイルからSpriteのリストを作成してアニメーションさせようと考えて実装してみました。

VideoNode.h
#import <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <2d/CCAnimation.h>


class VideoNode
{
public:
    static VideoNode* create();
    void initWithFile(const std::string &fileName);
    void play(bool repeat);
    cocos2d::Sprite* getSprite(){
        return this->sprite;
    }
private:
    void splitMovie(const std::string fileName, std::vector<cv::Mat> &mVec);
    void cvMat2ccImage(cv::Mat &src, cocos2d::Image &dst);
    cocos2d::Sprite* sprite;
    cocos2d::Animate *action;
};

実装部分は

VideoNode.cpp

#include "VideoNode.h"


VideoNode* VideoNode::create()
{
    VideoNode* node = new (std::nothrow)VideoNode();

    return node;
}

void VideoNode::initWithFile(const std::string &fileName)
{
    //MP4のfileNameから画像バッファを取得

    std::vector<cv::Mat> images;
    splitMovie(fileName, images);

//    //アニメーションクラスの作成
    auto animation = cocos2d::Animation::create();
//    
//    //ループでアニメーションクラスにaddSpriteFrameしていく
//    
    for (int i=0; i < images.size(); i++) {
        //newで動的にImage分のメモリを確保
        cocos2d::Image *img = new cocos2d::Image();
        cv::Mat m = images[i];
        //確保したimgのアドレスの中身を渡す。
        cvMat2ccImage(m, *img);

        cocos2d::Texture2D *tex = new cocos2d::Texture2D();
        tex->initWithImage(img);
        auto rect = new cocos2d::Rect();
        rect->setRect(0, 0, img->getWidth(), img->getHeight());
        cocos2d::SpriteFrame *frame = cocos2d::SpriteFrame::createWithTexture(tex, *rect);
        if(i==0){
            cocos2d::Sprite *sprite = cocos2d::Sprite::createWithSpriteFrame(frame);
            sprite->setName("animSprite");
            this->sprite = sprite;
        }
        animation->addSpriteFrame(frame);
   }
    action = cocos2d::Animate::create(animation);

}

void VideoNode::play(bool repeat)
{
    auto anime = cocos2d::RepeatForever::create(action);
    this->sprite->runAction(anime);
}

//cvMatからcocos2d::Imageに変換するメソッド
void VideoNode::cvMat2ccImage(cv::Mat &src, cocos2d::Image &dst)
{
    unsigned char *srcData;
    int width = src.cols;
    int height = src.rows;


    srcData = (unsigned char *)src.data;
    unsigned long size = 3 * width * height;
    dst.initWithRawData(srcData, size, width, height, 24);
}

//映像からcv::Matのデータ群を取得するメソッド
void VideoNode::splitMovie(const std::string fileName, std::vector<cv::Mat> &mVec)
{
    CvCapture *capture = cvCreateFileCapture(fileName.c_str());
    if(!capture)
    {
        std::cerr << "cvCreateFileCapure filed" << std::endl;
    }

    int rows = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
    int cols = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);


    IplImage *frame =NULL;
    cv::Mat m(rows, cols, CV_8UC3);

    while ((frame=cvQueryFrame(capture))!=NULL) {
        m = cv::cvarrToMat(frame);
        mVec.push_back(m);
    }
}

みたいな感じで実装してみました。これでいける!って思ったんですけど

なんで、何も表示されない!?

コンソールを見てみるとなんかwarningがでてる

jpeg error: Wrong JPEG library version: library is 62, caller expects 90
size = 0

とか、

libpng warning: Application built with libpng-1.6.16 but running with 1.5.12

とかでてるよ....

どうも調べてみるとOpenCVではビルド時にlibpng 1.5.12使ってて、cocos2d-xはlibpng 1.6.16使ってるのが原因っぽそう。

でもiOS向けにOpenCVビルドし直せば行けるかな?って思ったけどlibpngとlibjpegどうやって指定すればいいか分からないんで結局できないよ。

ってなりました。

誰か良い解決案がありましたらぜひ教えてください。

2015.6.14追記
解決法とコードを修正したものまとめましたので
ここを見てください。