2011年2月27日日曜日

Mac OS X + Android + OpenCV2.2

参照:Android - OpenCV Wiki
Ubuntu 10.10 + Android + OpenCVの環境をセットアップ(hironemu's blog)

この前「hironemu」さんのブログを参照して自分の環境でAndroid+OpenCV2.2をセットアップしてみて簡単なエッジ効果を試してみたのを今日まとめてみた。

1. 事前に確認するUtility

「swig」、「swig-java」、「apache-ant」、「cmake」
自分の環境で入ってなかったらインストールしておく。
僕はMacPortsからインストールしました。
$ sudo port install swig
$ sudo port install swig-java
$ sudo port install cmake
「swig」と「swig-java」のactiveバージョンが合わないとエラーになるので、
activeバージョンを合わせ

2. NDK

http://developer.android.comで落とした「ndk r4」ではC++の問題で動かないらしい。
(r5はC++サポートしているのでいけるかなと思ったら、ビルド方法が面倒でやめた。)

「http://www.crystax.net/android/ndk-r4.php」サイトで
C++サポートするようにカスタマイズされた Android NDK r4 を落とす。

ndkが「$HOME/android-ndk-r4-crystax」じゃないとダメらしい。
気に入らないが $HOMEにリンクを作る。

3. OpenCV2.2

OpenCVソース取得。
参照サイトにはSVNから落とすように書いてあるが、ビルドで失敗する可能性があるので、
2.2の安定バージョンのソースを落とした。「http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.2/」

落としたのを好きな場所に解凍してビルドする。

OpenCV Wikiのビルド手順
$ cd opencv/android
$ mkdir build
$ cd build
$ cmake ..
$ make

4. android-jni

Android NDKで使用する「android-opencv」を生成する。
$ cd opencv/android/android-jni
$ make
実行後、生成された「local.env.mk」ファイルの
「ANDROID_NDK_ROOT」項目を自分の環境に合わせて変更して、もう一回「make」(hironemu's blog参照)

「opencv/android/android-jni/libs」に
「armeabi/libandroid-opencv.so」、「armeabi-v7a/libandroid-opencv.so」ファイルができたら成功。



5. エッジ効果を試す。

エッジ効果をテストしたアプリのスクリーンショットはこちら。
元の画像
エッジ効果した画像
問題なく動くが、やはり実機でしか動かなかった。

OpenCVアプリを作るときは
OpenCV Wikiに書いてあるように「project_create.sh」を実行するか
自分で作るなら、NDKの設定で「Android.mk」にOpenCVのライブラリとヘッダのパスを追加する。
#Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := OpenCVUtil
LOCAL_SRC_FILES := babukuma_opencv_util.c
LOCAL_LDLIBS    := -lm -llog

#define OPENCV_INCLUDES and OPENCV_LIBS
PATH_TO_OPENCV_ANDROID_BUILD := ~/dev/OpenCV-2.2.0/android/build
include $(PATH_TO_OPENCV_ANDROID_BUILD)/android-opencv.mk

LOCAL_LDLIBS += $(OPENCV_LIBS)
    
LOCAL_C_INCLUDES +=  $(OPENCV_INCLUDES) 

include $(BUILD_SHARED_LIBRARY)
これなら問題なく「ndk-build」でビルドされる。

以下は作ったソース。。
/**
 * OpenCVUtil.java
 */
package com.babukuma.android.demo.opencv.jni;

/**
 * @author babukuma
 * 
 */
public final class OpenCVUtil {
 static {
  System.loadLibrary("OpenCVUtil");
 }

 /**
  * エッジ効果。
  * 
  * @param picData
  *            RGBのピクセルデータ
  * @param width
  *            画像のWidth
  * @param height
  *            画像のHeight
  */
 public static native void edge(int[] picData, int width, int height);
}
/**
 * EdgeActivity.java
 */
package com.babukuma.android.demo.opencv.activity;

import static com.babukuma.android.demo.opencv.Main.LOG_TAG;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

import com.babukuma.android.demo.opencv.R;
import com.babukuma.android.demo.opencv.jni.OpenCVUtil;

/**
 * エッジ効果テスト用Activity
 * 
 * @author babukuma
 */
public class EdgeActivity extends Activity {
 private ImageView picView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Log.d(LOG_TAG, "EdgeActivity#onCreate");

  setContentView(R.layout.edge);

  picView = (ImageView) findViewById(R.id.picView);
  picView.setOnClickListener(new OnClickListener() {

   public void onClick(View v) {
    Log.d(LOG_TAG, "picView#1onClick");
    BitmapDrawable db = (BitmapDrawable) picView.getDrawable();
    Bitmap bitmap = db.getBitmap();
    // Bitmap.Config.ARGB_8888
    Bitmap copyBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
    int width = copyBitmap.getWidth();
    int height = copyBitmap.getHeight();
    int[] pixels = new int[width * height];
    copyBitmap.getPixels(pixels, 0, width, 0, 0, width, height);

    Log.d(LOG_TAG, "OpenCVUtil#edge");
    OpenCVUtil.edge(pixels, width, height);

    Log.d(LOG_TAG, "finish OpenCVUtil#edge");
    copyBitmap.setPixels(pixels, 0, width, 0, 0, width, height);

    picView.setImageBitmap(copyBitmap);
   }
  });
 }
}
/*
 * babukuma_opencv_util.h
 */
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_babukuma_android_demo_opencv_jni_OpenCVUtil */

#ifndef _Included_com_babukuma_android_demo_opencv_jni_OpenCVUtil
#define _Included_com_babukuma_android_demo_opencv_jni_OpenCVUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_babukuma_android_demo_opencv_jni_OpenCVUtil
 * Method:    edge
 * Signature: ([III)V
 */
JNIEXPORT void JNICALL Java_com_babukuma_android_demo_opencv_jni_OpenCVUtil_edge
  (JNIEnv *, jclass, jintArray, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
/*
 * babukuma_opencv_util.c
 */
#include <stdio.h>

// JNI
#include<jni.h>

// Android
#include <android/log.h>

// OpenCV
#include <opencv/cv.h>

#include "babukuma_opencv_util.h"

// Android LOG
#define  LOG_TAG    "OpenCVDemo"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

// 関数定義
IplImage* pixels2IplImage(int* pixels, int width, int height);
void iplImage2Pixcels(int *pixcels, IplImage *srcImage);


/*
 * エッジ効果。
 * 「picData」データは必ず「ARGB」
 *
 * Class:     com_babukuma_android_demo_opencv_jni_OpenCVUtil
 * Method:    edge
 * Signature: ([III)V
 */
JNIEXPORT void JNICALL Java_com_babukuma_android_demo_opencv_jni_OpenCVUtil_edge
  (JNIEnv *env, jclass class, jintArray picData, jint width, jint height)
{
 LOGD("call Java_com_babukuma_android_demo_opencv_jni_OpenCVUtil_edge");

 jboolean isCopy;

 //Colorの配列を取り出す(配列のポインタを取得)
 jint* picDataPtr = (*env)->GetIntArrayElements(env, picData, &isCopy);

 //Color(int) の配列から、IplImageを作る
 LOGD("call pixels2IplImage");
 IplImage *srcImage = pixels2IplImage(picDataPtr, width, height);

 //画像の作成完了。
 LOGD("CV_BGR2GRAY");
 IplImage *wordImage=cvCreateImage(cvGetSize(srcImage),IPL_DEPTH_8U,1);
 cvCvtColor(srcImage, wordImage, CV_BGR2GRAY);
 LOGD("cvReleaseImage srcImage");
 cvReleaseImage(&srcImage);
 srcImage = NULL;

 // Detect edge
 LOGD("Detect edge");
 IplImage *wordImage2 = cvCreateImage(cvGetSize(wordImage), IPL_DEPTH_8U, 1);
 cvCanny(wordImage, wordImage2, 64, 128, 3);
 cvReleaseImage(&wordImage);
 LOGD("cvReleaseImage wordImage");
 cvReleaseImage(&wordImage);
 wordImage = NULL;


 // Convert black and whilte to 24bit image then convert to UIImage to show
 IplImage *edgedImage = cvCreateImage(cvGetSize(wordImage2), IPL_DEPTH_8U, 3);
 int y, x;
 for(y=0; y<wordImage2->height; y++) {
  for(x=0; x<wordImage2->width; x++) {
   char *p = edgedImage->imageData + y * edgedImage->widthStep + x * 3;
   *p = *(p+1) = *(p+2) = wordImage2->imageData[y * wordImage2->widthStep + x];
  }
 }
 LOGD("cvReleaseImage wordImage2");
 cvReleaseImage(&wordImage2);
 wordImage2 = NULL;

 //IplImageの値を、int配列に戻す
 LOGD("call iplImage2Pixcels");
 iplImage2Pixcels(picDataPtr, edgedImage);

 LOGD("cvReleaseImage edgedImage");
 cvReleaseImage(&edgedImage);
 edgedImage = NULL;

 (*env)->ReleaseIntArrayElements(env, picData, picDataPtr, 0);
}

// jint配列からIplImageを作成
// alphaは捨てる。
IplImage* pixels2IplImage(int *pixels, int width, int height) {
 int x, y, index;

 IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
 unsigned char* base = (unsigned char*) (img->imageData);
 unsigned char* ptr;

 for (y = 0; y < height; y++) {
  ptr = base + y * img->widthStep;
  for (x = 0; x < width; x++) {
   index = x + y * width;
   // B
   ptr[3 * x] = pixels[index] & 0xFF;
   // G
   ptr[3 * x + 1] = pixels[index] >> 8 & 0xFF;
   // R
   ptr[3 * x + 2] = pixels[index] >> 16 & 0xFF;
   // A
   // pixels[index] >> 24 & 0xFF;
  }
 }
 return img;
}

// IplImageからjint配列作成
void iplImage2Pixcels(int *pixcels, IplImage *srcImage)
{
    int x, y;
    int w,h;
    w=srcImage->width;
    h=srcImage->height;

    unsigned char* base = (unsigned char*) (srcImage->imageData);
    unsigned char* ptr;
    for (y = 0; y < h; y++)
    {
        ptr = base + y * srcImage->widthStep;
        for (x = 0; x < w; x++)
        {
            pixcels[x + y * w] =
              (0xFF000000) | // A
              (ptr[3 * x + 2] << 16) | // R
              (ptr[3 * x + 1] << 8) | // G
              (ptr[3 * x]); // B
        }
     }
}

彼女もエッジ効果させてみました。
怖い彼女になった。

2011年2月21日月曜日

iOS SDK 4.2で実機はiOS4.2.1の場合の問題

From Evernote:

iOS SDK 4.2で実機はiOS4.2.1の場合の問題

iOS SDK 4.2で実機はiOS4.2.1の場合、
iPhoneエミュレータで問題なく動作したのが、実機ではいろいろ問題が発生した。
解決した方法をメモする。



Warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1 (8C148)/Symbols/usr/lib/info/dns.so (file not found).
エラー

$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2\ \(8C134\)/Symbols/usr/lib/info /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1\ \(8C148\)/Symbols/usr/lib



warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1 (8C148)/Symbols/System/Library/AccessibilityBundles/AccessibilitySettingsLoader.bundle/AccessibilitySettingsLoader (file not found).
エラー

$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2\ \(8C134\)/Symbols/System/Library/AccessibilityBundles /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1\ \(8C148\)/Symbols/System/Library/AccessibilityBundles



warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1 (8C148)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
エラー

$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2\ \(8C134\)/Symbols/Developer /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1\ \(8C148\)/Symbols/Developer



2011年2月17日木曜日

RGB Color Blending

From Evernote:

RGB Color Blending


uint8_t backR, backG, backB; // Background画像のピクセル
unit8_t foreR, foreG, foreB; // Foreground画像のピクセル
unit8_t alpha; // アルファ

があるとして

unit8_t newR = backR + (((foreR - backR) * alpha) / 256);
unit8_t newG = backG + (((foreG - backB) * alpha) / 256);
unit8_t newB = backB + (((foreB - backB) * alpha) / 256);

2011年2月15日火曜日

OpenCV2.2をインストールした。

From Evernote:

OpenCV2.2をインストールした。

MacPortsからOpenCV2.2をインストール

MacPortsのport tree更新
$ sudo port selfupdate

OpenCVインストール
$ sudo port install opencv

OpenCVをPython2.6にバインディング(python使わないなら要らない)
$ sudo port -v install opencv +python26

インストール結果を確認すると
「/opt/local/bin」にユーティリティ
(opencv_createsamples,  opencv_haartraining, opencv_performance, opencv_traincascade)
「/opt/local/lib」にライブラリ
「/opt/local/include/opencv」にヘッダ
がインストールされている。


OpenCVの確認の為、あるサンプルをテストしてみる。
参照したサンプルは

この本のソースをOpenCV2.2用に修正したもの。


Command Line Tool プロジェクトを作成する。



有効なアーキテクチャを「i386」「x86_64」にする。



ヘッダ検索パスに「/opt/local/include」を追加

OpenCVグループを作って、「/opt/local/lib」のOpenCVライブラリを追加


「main.c」
#include <stdio.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>

int main (intargcconstchar * argv[]) {
char* szWndName="カメラ映像";
CvCapture* capture;
IplImage* img;
capture = cvCaptureFromCAM(0); // カメラ映像取得
if (capture==NULL) {
fprintf(stderr, "カメラが見つかりません。\n");
return -1;
}
cvNamedWindow(szWndName, CV_WINDOW_AUTOSIZE);
while (1) {
img=cvQueryFrame(capture); // フレーム取得
cvShowImage(szWndName, img); // フレーム表示
if(cvWaitKey(1)>=0) { // 何かキーを押したら終了
break;
}
}
cvDestroyWindow(szWndName);
cvReleaseCapture(&capture);
    return0;
}


実行するとMacのカメラで自分の顔が映る。




2011年2月14日月曜日

Linuxにffmpegをインストール

From Evernote:

Linuxにffmpegをインストール

■ Linux(CentOS5.5)にffmpegをインストール。


LAME 3.98.4 http://lame.sourceforge.net/ MP3への変換ライブラリ
FAAC / FAAD2 1.28 / 2.7 http://www.audiocoding.com/ MPEG2-AAC, MPEG4-AAC 音声圧縮ライブラリ
opencore-amr 0.1.2 http://opencore-amr.sourceforge.net/ 3G携帯用音声コーデック
ffmpeg 0.6.1 http://www.ffmpeg.org/

ffmpeg 0.6.1
では「liba52」が要らなくなった。(バージョン0.5から無くなったらしい)
理由:native ac3 encoderを持ってるらしい。


1. LAMEインストール
# tar xzvf lame-3.98.4.tar.gz
# cd lame-3.98.4
# ./configure
# make
# make instll

2. FAACインストール
「configure」がない為、「bootstrap」で生成する。
# tar xzvf faac-1.28.tar.gz
# cd faac-1.28
# ./bootstrap
# ./configure
# make
# make instll

3. FAAD2インストール
# tar xzvf faad2-2.7.tar.gz
# cd faad2-2.7
# ./configure
# make
# make instll

4. opencore-amrインストール
# tar xzvf opencore-amr-0.1.2.tar.gz
# cd opencore-amr-0.1.2
# ./configure
# make
# make instll

5. ffmpegインストール
# cd ffmpeg-0.6.1
# ./configure --enable-libmp3lame --enable-libfaac --enable-libfaad --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-gpl --enable-nonfree --enable-version3
# make
# make install


FAACインストール時発生した問題
# ./bootstrap
./bootstrap: line 3: aclocal: command not found
./bootstrap: line 4: autoheader: command not found
./bootstrap: line 8: libtoolize: command not found
./bootstrap: line 10: automake: command not found
./bootstrap: line 11: autoconf: command not found

この問題は 「automake」、「libtool」がインストールされていない為発生する。
「automake」、「libtool」をインストールして解決
# yum install automake
# yum install libtool


opencore-amrインストール時発生した問題

configureでエラーが発生
configure: error: C++ compiler cannot create executables
C++コンパイラが入ってないらしい。
「gcc-c++」をインストールして解決
# yum install gcc-c++


ffmpeg実行時
「ffmpeg: error while loading shared libraries: libfaac.so.0: cannot open shared object file: No such file or directory」エラーが発生すると。
ライブラリを登録する。

# vi /etc/ld.so.conf
行末に「/usr/local/lib」を追加
# /sbin/ldconfig


Unknown encoder 'png'
エラーが発生する。

「libpng-dev」をインストールして解決
# yum install libpng-dev

ffmpegの再インストールが必要