のどあめ

ググってもなかなか出てこなかった情報を垂れ流すブログ。

Boost.Pythonを使ってC++からSparse Codingする.

人生のうちで,1度や2度,C++のプログラムでSparseCodingしたいときがあると思います.しかし,昨今機械学習の分野で優遇されているのはPythonばかりです.

Sparse CodingについてはPythonではscikit learnを使えば簡単に使えます.
sklearn.decomposition.DictionaryLearning — scikit-learn 0.15.2 documentation

しかし,C++だとMLPACK等のライブラリを別途入れる必要があります.
MLPACKは動作環境がwindowsだったりすると,導入は非常に困難です(私は諦めました).
また,人生のうち1度や2度しか使わないのでいちいち新しいライブラリを導入するのは正直面倒です.

こんなときは,Boost.Pythonを介してscikit learnを使うという荒業を使えば,
手軽にC++からSparseCodingをすることが可能です.
これはscikit learnやscipyに実装されているものならなんでもC++から使えてしまう方法なので,非常に便利だと思います.

今回は,Boost.Pythonを使ったSparse Codingを使って,手書き数字認識に挑戦してみたいと思います.

概要

手書き数字認識

今回は,データセットとしてMNISTを利用します.
訓練画像・テスト画像とも28x28の手書き数字(0〜9)です.
噂のDeep Learningを使えば99.7%以上の精度が出るみたいです.
すごいですね(小並感)

Sparse Coding

理論面は私もよくわかってないので省略します.
参考:scikit-learnでSparse CodingとDictionary Learning -理論編- - takminの書きっぱなし備忘録

Sparse Codingによる手書き文字認識

文献[1]のインスパイアで,訓練データをそのまま辞書として使ってスパースコーディングします.
テストデータと同じクラスの訓練データの基底の係数が非ゼロになることを期待しています.
もしかすると同じような考えのもとに誰かが手書き文字認識されているかもしれませんが,あまり気にしません.

Boost.Python

本来はPythonからC/C++のコードを呼び出すものですが,逆も可能です.
Python自体にC/C++用のインタフェースがありますが,Boost.Pythonを使うとより簡単に使えます.

実装

sparse_coding.py

# -*- coding: utf-8 -*-
import numpy as np
from sklearn.decomposition import SparseCoder

def sparse_coding(dict,data,transform_n_nonzero_coefs=10,transform_algorithm='lars',transform_alpha=1.0):
    coder = SparseCoder(dictionary=dict,transform_algorithm=transform_algorithm,transform_n_nonzero_coefs=transform_n_nonzero_coefs,transform_alpha=transform_alpha)
    return coder.transform(data)

こちらの関数をC++から呼び出します.

mnist.cpp

OpenCVとBoostを利用しています.

#define BOOST_PYTHON_STATIC_LIB
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

#include <python.h>
#include <numpy/arrayobject.h>
#include <boost/python.hpp>
#include <boost/python/numeric.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

#include <boost/progress.hpp>

#include <iostream>
#include <fstream>
#include <vector>
#include <opencv2/opencv.hpp>

typedef unsigned char BYTE;
const unsigned int NUM_TRAIN = 5000;
const unsigned int NUM_TEST = 500;

inline void endian_swap(unsigned int& x) {
    x = (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
}

void loadImages(const std::string& path,cv::OutputArray image,unsigned int n_max=INT_MAX) {
  std::ifstream ifs(path,std::ios::binary);
  if(!ifs){
    std::cout << path <<" is not found." << std::endl;
    exit(1);
  }

  unsigned int magic_number,num_of_items,height,width;
  ifs.read((char*)&magic_number,sizeof(unsigned int));
  ifs.read((char*)&num_of_items,sizeof(unsigned int));
  ifs.read((char*)&height,sizeof(unsigned int));
  ifs.read((char*)&width,sizeof(unsigned int));

  //big-endianなのでlittle-endianに変更
  endian_swap(magic_number);
  endian_swap(num_of_items);
  endian_swap(height);
  endian_swap(width);

  num_of_items = std::min(num_of_items,n_max);
  unsigned int n_bytes=num_of_items*height*width;
  std::vector<BYTE> buf(n_bytes);
  ifs.read((char*)&buf[0],n_bytes);

  std::cout << "=== load images ===" << std::endl;
  std::cout << "path : "<< path  << std::endl;
  std::cout << "magic_number: "<< magic_number  << std::endl;
  std::cout << "num_of_items: "<< num_of_items  << std::endl;
  std::cout << "height: "<< height  << std::endl;
  std::cout << "width: "<< width  << std::endl;

  cv::Mat m(buf);

  m = m.reshape(1,num_of_items);
  m.convertTo(m,CV_64FC1);
  m.copyTo(image);
}

void loadLabels(const std::string& path,cv::OutputArray labels,unsigned int n_max=INT_MAX){
  std::ifstream ifs(path,std::ios::binary);
  if(!ifs){
    std::cout << path <<" is not found." << std::endl;
    exit(1);
  }

  unsigned int magic_number,num_of_items;
  ifs.read((char*)&magic_number,sizeof(unsigned int));
  ifs.read((char*)&num_of_items,sizeof(unsigned int));
  endian_swap(magic_number);
  endian_swap(num_of_items);
  num_of_items = std::min(num_of_items,n_max);

  unsigned int n_bytes=num_of_items;
  std::vector<BYTE> buf(n_bytes);
  ifs.read((char*)&buf[0],n_bytes);

  std::cout << "=== load labels ===" << std::endl;
  std::cout << "path : "<< path  << std::endl;
  std::cout << "magic_number: "<< magic_number  << std::endl;
  std::cout << "num_of_items: "<< num_of_items  << std::endl;

  cv::Mat m(buf);
  m = m.reshape(1,1);
  m.convertTo(m,CV_32SC1);
  m.copyTo(labels);
}


int main(int argc,char* argv[]){
  if(argc!=2){
    std::cout << "usage : " << argv[0] << " MNIST_path" <<std::endl;
    return -1;
  }

  std::string MINIST_path(argv[1]);
  std::string train_images_path = MINIST_path+"/train-images-idx3-ubyte";
  std::string train_labels_path = MINIST_path+"/train-labels-idx1-ubyte";
  std::string test_images_path  = MINIST_path+"/t10k-images-idx3-ubyte";
  std::string test_labels_path  = MINIST_path+"/t10k-labels-idx1-ubyte";

  //dataset load
  cv::Mat train_images, train_labels;
  loadImages(train_images_path,train_images,NUM_TRAIN);
  loadLabels(train_labels_path,train_labels,NUM_TRAIN);

  cv::Mat test_images, test_labels;
  loadImages(test_images_path,test_images,NUM_TEST);
  loadLabels(test_labels_path,test_labels,NUM_TEST);

  //predictのために工夫 : [1,2,3]を[1,0,0; 0,1,0; 0,0,1]に変換
  cv::Mat dot_mat;
  for(int i = 0;i < 10;i++){
    cv::Mat mask = (train_labels == i);
    mask.convertTo(mask,CV_64FC1);
    dot_mat.push_back(mask);
  }
  dot_mat/=255;

  std::cout << "=== test ===" << std::endl;
  {
    //sparce coding
    cv::Mat X;

    try{
      boost::progress_timer t;
      namespace bp = boost::python;

      Py_Initialize();

      // おまじない
      bp::numeric::array::set_module_and_type("numpy", "ndarray");
      bp::class_<std::vector<double>>("std::vector<double>")
        .def(bp::vector_indexing_suite<std::vector<double>>());

      // 利用するpyファイルの指定
      bp::object global_ns = bp::import("__main__").attr("__dict__");
      bp::exec_file("sparse_coding.py", global_ns, global_ns);

      // cv::Matからboost::python::numeric::arrayに変換
      std::vector<double>train_images_vec = train_images.reshape(1,1);
      bp::numeric::array dict(train_images_vec);
      dict.resize(train_images.rows,train_images.cols);

      std::vector<double>test_images_vec = test_images.reshape(1,1);
      bp::numeric::array data(test_images_vec);
      data.resize(test_images.rows,test_images.cols);

      // 呼び出す関数を指定
      bp::object py_func = global_ns["sparse_coding"];

      // pythonの関数を呼び出し
      bp::object py_val = py_func(dict,data,9); 
      
      // 戻り値をcv::Matに変換
      bp::numeric::array py_arr_val = bp::extract <bp::numeric::array>(py_val);

      PyArrayObject* py_arr_obj = (PyArrayObject*)(py_arr_val.ptr());

      double* data_ptr = (double*)(PyArray_DATA(py_arr_obj));

      npy_intp* dims = PyArray_DIMS(py_arr_obj);

      std::vector<double> vec_val(data_ptr, data_ptr + (dims[0]*dims[1]));

      std::cout << vec_val.size() << std::endl;
      cv::Mat m(vec_val);
      m = m.reshape(1,dims[0]);
      m.copyTo(X);// vec_valが開放されても大丈夫なようにdeep copy

      std::cout << "calc time : ";//boost::progres_timer
    }
    catch (...){
      PyErr_Print();
    }

    //predict
    int nT = 0, nF = 0;

    int* gtl=test_labels.ptr<int>(0);
    for(int i = 0;i < test_images.rows;i++){
      std::cout << "[";
      double max_p = 0.0;
      int max_d = -1;
      for(int d = 0;d < 10;d++){
        double p = X.row(i).dot(dot_mat.row(d));
        if(p > max_p){
          max_p = p;
          max_d = d;
        }
        std::cout << p << ",";
      }
      std::cout << "] predict("<< max_d <<")";
      std::cout << " GT(" << gtl[i] << ") " << std::endl;

      (gtl[i] == max_d)? nT++ : nF++;
    }

    std::cout << "Accuracy : " << 1.0*nT/(nT+nF) << std::endl;
  }
}

全データを使うと学習に時間がかかるので,学習データ5000,テストデータ500でやっています.
また,predict部分では係数の合計を認識スコアとして使っています.

ビルド&使い方

clang++ -std=c++11 -lboost_python $(shell python-config --cflags) $(shell pkg-config --libs opencv) mnist.cpp -o mnist.out
./mnist.out data

↑でdataはデータセットを入れたディレクトリへのパスです.

python-config
||
**出力
>||
(前略)
calc time : 86.88 s
[0,0,0,0,0,0,0,0.658375,0,0,] predict(7) GT(7)
[0,0,0.539294,0.0822132,0,0,0,0,0,0,] predict(2) GT(2)
[0,0.167486,0,0,0,0,0,0,0,0,] predict(1) GT(1)
[0.426151,0,0,0,0,0,0,0,0,0,] predict(0) GT(0)
[-0.0978972,0,0,0,0.235536,0,0,0,0,0.0391382,] predict(4) GT(4)
(中略)
[0,0,0,0,0,0,0,0,0,0.426833,] predict(9) GT(9)
[0,0,0,0,0.147261,0,0,0.0295174,0.275997,0,] predict(8) GT(4)
[0.394697,0,0,0,0,0,0,0,0.0479334,0,] predict(0) GT(0)
[0,0,0,0,0,0,0.19342,0,0.0134353,0,] predict(6) GT(6)
Accuracy : 0.902

精度は90.2%になりました.
うーん・・・学習データを全部使っていないとはいえイマイチですね.
やはりオーソドックスに辞書学習と組み合わせるほうが良さそうですね.

また,sparse_codingのtransform_n_nonzero_coefsの値によって精度が大きく変わりました.
大きくても小さくてもダメなようで,今回は一番精度の良かった9を使いました(これはひどい

今回のまとめ

Boost.Pythonを使うことでPythonで実装されている関数をC++から使うことができました.
今回はMacで動かしましたが,WindowsでもPyhtonをインストールすれば動かす事ができます.

しかし,体感ですがやはりC++Pythonのデータのやり取りにはそれなりに時間がかかるようです(大きい行列だと1分とか・・・).
何かをちょこっと試したいという場合に,ライブラリのインストールと格闘とする前に試してみるくらいには使えると思います.

でも,機械学習をしたい人は最初からPythonでプログラミングしましょう.

参考文献

[1] J. Wright, A. Y. Yang, A. Ganesh, S. S. Sastry, and Y. Ma: "Robust face recognition via sparse representation." (2009)

OpenCV 3.0.0 alpha で Dense samplingする

さて,OpenCV 3.0.0 alphaがリリースされて結構たちましたね.
研究室のうちのグループでは調子に乗って一足先にグループ内ライブラリにOpenCV 3.0.0-alphaを取り入れましたが,あれがないこれがない,などと色々と困ったことになったりしました.

さて,その中のうちの一つとして「OpenCV3.0.0 alphaからDense Samplingがなくなった」というものがあります.
参考:OpenCV3.0.0-alphaの特徴抽出・マッチングまとめ - whoopsidaisies's diary

これは,Bag-of-featuresの時代は終わったということなのでしょうか・・・

まあ,Dense Samplingぐらいすぐ実装できる,と思っていたのですが,
いざやってみると結構躓いたので記事にしました.

Dense Samplingの実装

OpenCVのcv::FeatureDetectorの子クラスとして,
Dense Samplingを実装しました.

DenseFeatureDetector.h

#pragma once

#include <opencv2/opencv.hpp>
namespace cv {
  class DenseFeatureDetector : public cv::FeatureDetector {
  public:
    struct Param{
      int xStep = 4;
      int yStep = 4;

      float initFeatureScale = 1.0f;
      int scaleLevels = 1;
      float featureScaleMul = 1.2f;

      int imgBoundX = 0;
      int imgBoundY = 0;

      bool varyXyStepWithScale = true;
      bool varyImgBoundWithScale = false;
      Param(){}
    }param;

    DenseFeatureDetector(){}
    DenseFeatureDetector(const Param& p)
      :param(p)
    {
    }

    static cv::AlgorithmInfo& _info();
    virtual cv::AlgorithmInfo* info()const override;

    virtual void detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask = cv::noArray()) const override;

    static cv::Ptr<FeatureDetector> create(const Param& p=Param()){
      return cv::Ptr<FeatureDetector>(new DenseFeatureDetector(p));
    }
  };
}

DenseFeatureDetector.cpp

#include "DenseFeatureDetector.h"

namespace cv{
#define CV_INIT_ALGORITHM(classname, algname, memberinit) \
  static inline ::cv::Algorithm* create##classname##_hidden() \
  { \
    return new classname; \
  } \
  \
  static inline ::cv::Ptr< ::cv::Algorithm> create##classname##_ptr_hidden() \
  { \
    return ::cv::makePtr<classname>(); \
  } \
  \
  static inline ::cv::AlgorithmInfo& classname##_info() \
  { \
    static ::cv::AlgorithmInfo classname##_info_var(algname, create##classname##_hidden); \
    return classname##_info_var; \
  } \
  \
  static ::cv::AlgorithmInfo& classname##_info_auto = classname##_info(); \
  \
  ::cv::AlgorithmInfo* classname::info() const \
  { \
    static volatile bool initialized = false; \
    \
    if( !initialized ) \
    { \
      initialized = true; \
      classname obj; \
      memberinit; \
    } \
    return &classname##_info(); \
  }

  CV_INIT_ALGORITHM(DenseFeatureDetector, "Dense",);

  void DenseFeatureDetector::detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask) const
  {
    cv::Mat maskMat = mask.empty() ? cv::Mat(image.size(), CV_8UC1, cv::Scalar(255)) : mask.getMat();
    cv::Mat imageMat = image.getMat();

    int width = imageMat.cols;
    int height = imageMat.rows;

    int nowBoundX = param.imgBoundX;
    int nowBoundY = param.imgBoundY;

    int nowXStep = param.xStep;
    int nowYStep = param.yStep;

    float nowFeatureSize = param.initFeatureScale;

    for (int s = 0; s < param.scaleLevels; s++){
      for (int y = nowBoundY; y < height; y += nowYStep){
        unsigned char* maskline = maskMat.ptr<unsigned char>(y);

        for (int x = nowBoundX; x < width; x += nowXStep){
          if (maskline[x] > 128){
            cv::KeyPoint kp;
            kp.pt = cv::Point(x, y);
            kp.size = nowFeatureSize;
            kp.response = 100.0f;
            keypoints.push_back(kp);
          }
        }
      }

      if (param.varyImgBoundWithScale){
        nowBoundX *= param.featureScaleMul;
        nowBoundY *= param.featureScaleMul;
      }
      if (param.varyXyStepWithScale){
        nowXStep *= param.featureScaleMul;
        nowYStep *= param.featureScaleMul;
      }
      nowFeatureSize *= param.featureScaleMul;
    }
  }
}

以上です.

使い方としては,

#include "DenseFeatureDetector.h"

int main(){
  cv::Mat img = cv::imread("lena.jpg");

  cv::DenseFeatureDetector::Param p;
  p.scaleLevels = 3;
  p.featureScaleMul = 1.5;
  p.xStep = 20;
  p.yStep = 20;
  cv::Ptr<cv::FeatureDetector> detector = cv::DenseFeatureDetector::create(p);

  std::vector<cv::KeyPoint> keypoints;
  detector->detect(img,keypoints);

  for(auto& k : keypoints){
    std::cout << "Pt : "<< k.pt << " Size :" << k.size << std::endl;
  }

  return 0;
}

出力

Pt : [0, 0] Size :1
Pt : [20, 0] Size :1
Pt : [40, 0] Size :1
Pt : [60, 0] Size :1
(中略)
Pt : [180, 270] Size :2.25
Pt : [225, 270] Size :2.25
Pt : [270, 270] Size :2.25
Pt : [315, 270] Size :2.25
Pt : [360, 270] Size :2.25

こんなかんじです.

cv::Algorithmを継承したクラスは基本的にCV_INIT_ALGORITHMを使う必要があるみたいですね.
(´・ω・`)知らんがな.
これに気づくまでに結構時間がかかりました.

本当はcv::FeatureDetector::create("Dense")みたいなことがしたいのですが,これはOpenCVを再コンパイルする必要があると思うので,今回はとりあえず使えればOKというスタンスで実装しました.

何にせよ,これを使えばOpenCV 3.0 alphaでもDense Samplingが出来るようになりました!めでたしめでたし.

なお,この実装はOpenCVのgitリポジトリがHEADだと動かないみたいなので,
3.0.0 alphaにチェックアウトしてから使ってください.

今回のまとめ

  • OpenCV 3.0 alpha をメインプログラムに使うのはやめよう
  • Dense Samplingしたい人はOpenCV 2.4.9を使おう

今回参考にしたWebページ


次回は,FisherVectorか,Sparse Codingについて記事を書きたいと思います.

cv::SVMのsampleIdxの使い方

先日OpenCVのcv::SVMを使っていた時に、引数のsampleIdx(とvarIdx)の使い方がリファレンスに載っていなかったので、メモついでに記事にしました。

SVMとは

(略)

cv::SVMコンストラクタもといtrainの引数について

リファレンスによると、

cv::SVM::train(
  const cv::Mat& trainData, 
  const cv::Mat& responses,
  const cv::Mat& varIdx=cv::Mat(),
  const cv::Mat& sampleIdx=cv::Mat(), 
  cv::SVMParams params=cv::SVMParams() 
)
  • trainData:学習に用いるサンプルの特徴量。n個のdim次元の特徴量を格納したn x dim のcv::Matで表す。
  • responses:学習に用いるサンプルのラベル。n個の-1または1の値を格納した1 x dim のcv::Matで表す。
  • varIdx:学習に用いる特徴量のindex。trainDataの特徴量の一部の次元のみを利用して学習したいときに用いる。
  • sampleIdx:学習に用いるサンプルのindex。trainDataの一部の行のみを利用して学習したいときに用いる。
  • params:svmのパラメータ。詳細はリファレンス参照。

という感じです。

利用例

#include <opencv2/opencv.hpp>

int main(){
    cv::Mat trainData = (cv::Mat_<float>(4,2) << 1,1, 2,2, -1,-1, -2,-1);
    cv::Mat responses = (cv::Mat_<float>(4,1) << 1,1, -1,-1);

    cv::Mat sampleIdx = (cv::Mat_<int>(2,1) << 0,2);
	
    cv::SVM svm;
    svm.train(trainData,responses,cv::Mat(),sampleIdx);

    std::cout << svm.predict((cv::Mat_<float>(1,2) << 3,2)) << std::endl;
}

こんな感じです。
#sampleIdxをn x 1のcv::Matを使って0,1で表現すると思って詰んだのは秘密・・・

MinGWのg++でコンパイルしたstd::coutを含むプログラムが強制終了する問題について

MinGW + gVim + QuickRunでテストプログラムを動かす環境を整えてみたら、
何故かMinGWコンパイルした一部のプログラムが強制終了することに気づきました。

#include <iostream>
int main(){
   std::cout << "a" << std::endl;
   return 0;
}

これが強制終了します(コンパイルは通る)。
他のPCのMinGWだとうまくいくのに・・・

今回は、この問題を解決する方法を見つけたので紹介します。


解決法1 : 静的ライブラリでコンパイル

>g++ test.cpp -static-libstd
>a.exe

これで動きました。

これは、つまりdllがおかしいということですね。

どうやら、STL関連のDLLはlibstdc++-6.dllとlibgcc_s_sjlj-1.dllの2つのようです。

ちゃんとパスが通っているか、再インストールしてみたらどうか、
色々と試してみましたが、問題は解決しませんでした。

しかし、ふと「libstdc++-6.dll」でファイル検索してみたところ、
なんとMinGWとは別のlibstdc++-6.dllが存在することを発見しました!!


解決法2 : dllの競合をなくす

どうやら、過去に入れた「Octave 3.6.4 for Windows MinGW」があるのに気が付かずに、
新たに最新版のMinGWを入れたのが問題だったようです。
Octave同封のlibstdc++-6.dllの方が先にパスを通していたので、
実行時にOctave側のdllを読みに行って落ちていたようです。

試しに、Octaveのパスを消してみると無事プログラムを動かすことが出来ました。
そして、今は特にOctaveを使う用事もないので、アンインストールすることで事なきを得ました。
(何の解決にもなってない)

Octaveを使う人は、VisualStudio版を使うか、MinGWのバージョンを合わせるか、
どちらかのパスを通さないかすればいいのではないでしょうか。


今回は結構うっかりな問題でしたが、
dllのバージョンが違う場合は強制終了せずに警告を出すぐらいしてくれても・・・

VisualStudio 2012のデバッグ中にOpenCVのcv::Matの中身を確認する方法

私はVisualStudioの拡張機能であるImageWatchを使っています。
ImageWatchはOpenCVで読み込んだ画像などをデバッグ中に可視化する事ができます。
ImageWatchはとても便利なのですが、大きなCV_64Fの二次元のcv::Mat型などの中身を見るのには不便です。

以下のようにコマンドウィンドウを用いる方法もありますが、

>? ((double*)mat.data)[mat.rows*4+2]

ある要素(上の場合は(4,2))を見たいだけならいいのですが、
内容をずらっと見たい時に不便ですし、何より入力するのが面倒です。

今回はImageWatchのnatvisを改造して、この問題に対処したいと思います。

natvisとは

公式ページによると、

  • VisualStudioデバッガの表示をカスタマイズするフレームワーク
  • 昔はautoexp.datがやっていた。
  • xml形式でかけるのでわかりやすい

ということみたいです。
ImageWatchを入れると、cv::Matのデバッグ表示が変わるのはこのためです。
今回はImageWatchのnatvisを改造してcv::Matの中身を一緒に表示させるようにします。

natvisの改造

ImageWatchのOpenCV関連のnatvisファイルはデフォルトで、

C:\Users\username\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\謎文字列?\ImageWatchOpenCV.natvis

に保存されています。

この中の以下のように改造します。
※念のためバックアップは取ってください。

・・・
  <Type Name="cv::Mat">
    <AlternativeType Name="cv::Mat_&lt;*&gt;"/>
    <DisplayString Condition="(flags&amp;7)==0">{{UINT8, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==1">{{INT8, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==2">{{UINT16, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==3">{{INT16, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==4">{{INT32, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==5">{{FLOAT32, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==6">{{FLOAT64, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==7">{{USER, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <Expand>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==0">
        <DisplayString>UINT8</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==1">
        <DisplayString>INT8</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==2">
        <DisplayString>UINT16</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==3">
        <DisplayString>INT16</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==4">
        <DisplayString>INT32</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==5">
        <DisplayString>FLOAT32</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==6">
        <DisplayString>FLOAT64</DisplayString>
      </Synthetic>
      <Item Name="[channels]">((flags&amp;0xfff)&gt;&gt;3)+1</Item>
      <Item Name="[width]">cols</Item>
      <Item Name="[height]">rows</Item>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 0 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 8U -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 1 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 8S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 2 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 16U -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 3 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 16S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 4 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 32S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 5 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 32F -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 6 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 64F -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
      <Item Name="[stride]">step.p[0]</Item>
      <Item Name="[continous]">(flags &amp; 16384) == 16384</Item>
      <Item Name="[submatrix]">(flags &amp; 32678) == 32678</Item>
      <Item Name="[refcount]">refcount</Item>
	  <Item Name="[data]">data</Item>
    </Expand>
  </Type>
・・・

natvisファイルではループ等は使えないため、ゴリゴリ書いています。
今回はcv::Matの中身を6行(上3行、下3行)を見るためのnatvisを(ゴリゴリ)書きました。
他にも色々と可視化したほうがいいような気もしますが、
私個人としてはcv::Matさえ確認できればそれで良いのでこのままです。

必要なら自分で足してください。


これを適用すると、こんな感じになります。
f:id:ykicisk:20131106140258p:plain

大きな行列の中身を見るときに便利になりました!
めでたしめでたし。

Ubuntu 12.04(64bit)にjperlを導入する方法

ちょっと前にjperlなるものを使わざるを得ない機会がありました。
その時に導入に一晩くらいかかってしまったので、その詳細を書いておきます。

そもそもjperlとは何なのか・・・

  • 昔々perlが日本語がうまく扱えないときに、その問題にある程度対処するために作られた
  • 今はencodingプログラマなるものを使えば問題ない
  • Perl 5.5までしか対応していない
  • 現場ではまだまだ現役のところも少なくない

つまり、負の遺産というわけですね・・・

Ubuntu 12.04(64bit)へのjperlの導入

まずは、こちらからperl5.005_04.tar.gzとjperl5.005_04-20040401.pat.gzをダウンロードして、
Webページの指示にしたがってPerlにJperlのパッチを当てる。

$ tar zxvf perl5.005_04.tar.gz
$ gzip -d jperl5.005_04-20040401.pat.gz
$ cd perl5.005_04
$ patch -p1 < ../jperl5.005_04-20040401.pat

次に、既存のperlとは別にperl5.005_04(jperl)をインストールする。

$ sh Configure -Dprefix=/usr/local/perl5.005_04 -Dusethreads -de

それから、

$ make

とするのですが、この段階でいくつかエラーが出るかもしれません(私はでました)。

<command-line>なんとかというエラー

makedependent.SHを編集すればOK

・・・
 '/^#.*<stdin>/d' \
 '/^#.*<builtin>/d' \
 '/^#.*<built-in>/d' \
 '/^#.*<command line>/d' \
 '/^#.*<command-line>/d' \  #この行を追加
 '/^#.*"-"/d' \
 's#\.[0-9][0-9]*\.c#'"$file.c#" \
・・・

math.hがリンクされていないみたいなエラー

sh Configureからやり直し。
■64bit

$ sh Configure -Dprefix=/usr/local/perl5.005_04 -Dusethreads -Dplibpth=/usr/lib/x86_64-linux-gnu -de

■32bit(未確認)

$ sh Configure -Dprefix=/usr/local/perl5.005_04 -Dusethreads -Dplibpth=/usr/lib/i386-linux-gnu -de

さらに、asm/page.hがないとか言われたらシンボリックリンクで対処します。

$ mkdir /usr/include/asm
$ sudo ln -s /usr/src/linux-headers-3.5.0-31/arch/x86/include/asm/page.h /usr/include/asm/page.h

linux-headersのバージョンは違うかもしれません。

そこから、

$ make test
$ sudo make install

して、最後にシンボリックリンクをつくれば完了!

$ sudo ln -s /usr/local/bin/perl5.005_04/bin/perl /usr/local/bin/jperl

実行中に rr_fopen error で /usr/tmp/...のファイルが開けないと言われたら
/usr/tmpディレクトリがないのが原因かもしれません。
その場合は、mkdirで作ってパーミッションを設定すればOKです。


以上です!
これでUbuntuでもjperlが使えます!!
たぶん!

今回の感想

  • jperlは一生使いません。
  • Redhat系は優秀

挨拶

私がプログラミング等でつまずいたところをメモするブログです。

同じ問題で苦しんでいる人の助けになれば幸いです・・・が、私自身はいろいろと力不足なので突っ込んだ質問などには答えられないかもしれません。

動けばそれで良いのです。

 

もし、誤り等あればコメントしていただければ幸いです。

それでは、よろしくお願いいたします。