OpenCV 3.0に果敢に挑戦し続けてみる

個人的な趣味の一環として、OpenCV 3.0がらみの情報をまとめてみる。「引用はいぃんよー、無断転載はあかんよー」ということで。

初音ミクさんをOpenCV上に召喚(仮)する(OpenCV 3.0.0-dev vizを使ってみる)

OpenCV 3.0.0からサポートしているvizモジュールを使ってみたよ!使ってみたけど、OpenCVとの関係性が全くないよ!釣記事だね!(嘘)

1.vizモジュールをinstallする

apt-get install libvtk5.8* でとにかく何でもかんでも入れて、cmakeしなおす。 

-   OpenCV modules:
--     To be built:                 core flann imgproc highgui features2d calib3d cudaarithm ml nonfree objdetect video contrib cudawarping cuda cudafilters cudaimgproc legacy cudabgsegm cudacodec cudafeatures2d cudaoptflow cudastereo optim photo shape softcascade stitching superres ts videostab viz
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 androidcamera cudalegacy cudev java matlab python
--
--   GUI:
--     QT:                          NO
--     GTK+ 2.x:                    YES (ver 2.24.20)
--     GThread :                    YES (ver 2.38.1)
--     GtkGlExt:                    NO
--     OpenGL support:              NO
--     VTK support:                 YES (ver 5.8.0)

なって、VTKが有効になる。

 

2.ミクさんを用意する

今回は、なんとなーく(点数が少ない方が楽なので)こちらのミクさんを。

http://tawaship.blog134.fc2.com/blog-entry-69.html#more

 

3.ミクさんをバラバラにする

バイナリフォーマットは、このあたりを参考にして、C言語(≠C++)で分解。

http://www.neo-tech-lab.co.uk/MikuMikuDance/PMD1.htm#PMD%E5%BD%A2%E5%BC%8F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0

音がなるので要注意っと。

 

4. VTKにぶちこむ

点情報をこうやってぶちこんだり

                points->InsertNextPoint(v.vertex[i].pos.x,

                                        v.vertex[i].pos.y,

                                        v.vertex[i].pos.z);

 

面情報をこうやってぶちこんだり

                vtkSmartPointer < vtkTriangle > triangle = vtkSmartPointer < vtkTriangle >::New();

                triangle->GetPointIds()->SetId(0, f.face_vert_index[i]);

                triangle->GetPointIds()->SetId(1,f.face_vert_index[i + 1]);

                triangle->GetPointIds()->SetId(2,f.face_vert_index[i + 2]);

                cells->InsertNextCell(triangle);

 

多分、材質情報を読み込んだり、色を変えたりするともっとそれらしくなるだろうけど、とりあえず”3D表示する"までできたので、満足してみる。

 

f:id:anobiidae:20140301091256p:plain

 

追記: Lat式ミクVer 2.31さん ( http://bowlroll.net/up/dl30199 ) もこの通り

f:id:anobiidae:20140301155320p:plain

 

Makefile

a.out : a.cpp

        g++ \

                -g \

                -O2 \

                -std=gnu++11 \

                -Wno-deprecated \

                -Wno-unused-result \

                a.cpp \

                -lvtkRendering -lvtkGraphics -lvtkIO -lvtkFiltering \

                -lvtkCommon -lvtksys -lpthread -lm\

                `pkg-config opencv --cflags --libs` \

                -I/usr/include/vtk-5.8/

 a.cpp

#include <cstdio>

#include <cstdint>

#include <iostream>

#include <opencv/cv.hpp>

#include <opencv2/viz.hpp>

#include <opencv2/viz/widget_accessor.hpp>

 

#include <vtkPoints.h>

#include <vtkTriangle.h>

#include <vtkCellArray.h>

#include <vtkPolyData.h>

#include <vtkPolyDataMapper.h>

#include <vtkIdList.h>

#include <vtkActor.h>

#include <vtkProp.h>

 

using namespace cv;

using namespace std;

 

class PMD:public viz::Widget3D {

  private:

    struct PMDHeader {

        uint8_t ID[3];

        float Version;

        uint8_t ModelName[20];

        uint8_t Comment[256];

    } __attribute__ *1;

 

    struct x_Vector {

        float x;

        float y;

        float z;

    } __attribute__ *2;

 

    struct x_Coords2d {

        float u;

        float v;

    } __attribute__ *3;

 

    struct PMD_vertex {

        x_Vector pos;

        x_Vector normal;

        x_Coords2d uv;

        uint16_t bone_num[2];

        uint8_t bone_weight;

        uint8_t edge_flag;

    } __attribute__ *4;

 

    struct PMDVertexList {

        uint32_t vert_count;

        PMD_vertex *vertex;

    } __attribute__ *5;

 

    struct PMDFaceList {

        uint32_t face_vert_count;

        uint16_t *face_vert_index;

    } __attribute__ *6;

 

    PMDHeader h;

    PMDVertexList v;

    PMDFaceList f;

 

  public:

    PMD(char *fname) {

        FILE *fp = fopen(fname, "r");

        vtkSmartPointer < vtkPoints > points =

            vtkSmartPointer < vtkPoints >::New();

        vtkSmartPointer < vtkCellArray > cells =

            vtkSmartPointer < vtkCellArray >::New();

        {                       // Header

            fread(&h, sizeof(h), 1, fp);

            printf("%c%c%c\n", h.ID[0], h.ID[1], h.ID[2]);

            printf("%f\n", h.Version);

        }

        {                       // Vertex

            fread(&v.vert_count, sizeof(uint32_t), 1, fp);

            printf("vertexs = %d\n", v.vert_count);

            v.vertex =

                (PMD_vertex *) malloc(sizeof(PMD_vertex) * v.vert_count);

            for (int i = 0; i < v.vert_count; i++) {

                fread(&v.vertex[i].pos.x, sizeof(float), 1, fp);

                fread(&v.vertex[i].pos.y, sizeof(float), 1, fp);

                fread(&v.vertex[i].pos.z, sizeof(float), 1, fp);

                fread(&v.vertex[i].normal.x, sizeof(float), 1, fp);

                fread(&v.vertex[i].normal.y, sizeof(float), 1, fp);

                fread(&v.vertex[i].normal.z, sizeof(float), 1, fp);

                fread(&v.vertex[i].uv.u, sizeof(float), 1, fp);

                fread(&v.vertex[i].uv.v, sizeof(float), 1, fp);

                fread(&v.vertex[i].bone_num[0], sizeof(uint16_t), 1, fp);

                fread(&v.vertex[i].bone_num[1], sizeof(uint16_t), 1, fp);

                fread(&v.vertex[i].bone_weight, sizeof(uint8_t), 1, fp);

                fread(&v.vertex[i].edge_flag, sizeof(uint8_t), 1, fp);

 

                points->InsertNextPoint(v.vertex[i].pos.x,

                                        v.vertex[i].pos.y,

                                        v.vertex[i].pos.z);

            }

        }

        { // faces

            fread(&f.face_vert_count, sizeof(uint32_t), 1, fp);

            printf("faces = %d\n", f.face_vert_count);

            f.face_vert_index =

                (uint16_t *) malloc(sizeof(uint16_t) * f.face_vert_count);

            for (int i = 0; i < f.face_vert_count; i++) {

                fread(&f.face_vert_index[i], sizeof(uint16_t), 1, fp);

            }

 

            for (int i = 0; i < f.face_vert_count; i += 3) {

                vtkSmartPointer < vtkTriangle > triangle =

                    vtkSmartPointer < vtkTriangle >::New();

                triangle->GetPointIds()->SetId(0, f.face_vert_index[i]);

                triangle->GetPointIds()->SetId(1,

                                               f.face_vert_index[i + 1]);

                triangle->GetPointIds()->SetId(2,

                                               f.face_vert_index[i + 2]);

                cells->InsertNextCell(triangle);

            }

        }

        fclose(fp);

 

 

        // http://docs.opencv.org/trunk/doc/tutorials/viz/creating_widgets/creating_widgets.html#creating-widgets

 

        // Create a polydata object

        vtkSmartPointer < vtkPolyData > polyData =

            vtkSmartPointer < vtkPolyData >::New();

 

        // Add the geometry and topology to the polydata

        polyData->SetPoints(points);

        polyData->SetPolys(cells);

 

        // Create mapper and actor

        vtkSmartPointer < vtkPolyDataMapper > mapper =

            vtkSmartPointer < vtkPolyDataMapper >::New();

#if VTK_MAJOR_VERSION <= 5

        mapper->SetInput(polyData);

#else

        mapper->SetInputData(polyData);

#endif

 

        vtkSmartPointer < vtkActor > actor =

            vtkSmartPointer < vtkActor >::New();

        actor->SetMapper(mapper);

 

        // Store this actor in the widget in order that visualizer can access it

        viz::WidgetAccessor::setProp(*this, actor);

 

        // Set the color of the widget. This has to be called after WidgetAccessor.

        setColor(viz::Color::red());

    }

 

    ~PMD() {

        // Leaked ...

    }

 

};

 

int main()

{

    char filename[] = "CHANxCO_style_MIKU.pmd";

    PMD *dat = new PMD(filename);

    viz::Viz3d myWindow("Viz Demo");

 

    myWindow.showWidget("TRIANGLE", *dat);

    myWindow.spin();

 

    return 0;

}

 

 

*1:packed

*2:packed

*3:packed

*4:packed

*5:packed

*6:packed