「OpenGLとOpenCVを使って画像を出力する」の説明

今回は、前回の記事で載せたソースの説明です。

まず、これが前回のソースです。

#include <stdlib.h>
#include <windows.h>

#include <glut.h>

#include <cv.h>
#include <highgui.h>

IplImage *image;

void init()
{
    // 画像の読み込み
    image = cvLoadImage("image.png", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
    if (image->nChannels >= 2){
        char buf;
        
        for (int i = 0; i < image->width * image->height * image->nChannels;
                i += image->nChannels){
            buf = image->imageData[i];
            image->imageData[i] = image->imageData[i + 2];
            image->imageData[i + 2] = buf;
        }
    }
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 画像の反転の修正
    glPixelZoom(1, -1);
    // 画像の位置の設定
    glRasterPos2f(-1, 1);
    
    // 画像出力
    switch (image->nChannels){
        case 1:
            // モノクロ画像だった場合
            glDrawPixels(image->width, image->height,
                GL_LUMINANCE, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 3:
            // 透過なしカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGB, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 4:
            // 透過ありカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGBA, GL_UNSIGNED_BYTE, image->imageData);
            break;
    }
    
    glFlush();
}

void idle()
{
    glutPostRedisplay();
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    init();
    
    glutInit(&__argc, __argv);
    
    glutInitWindowSize(image->width, image->height);
    glutInitDisplayMode(GLUT_RGBA);
    glutCreateWindow("test");
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    
    glutMainLoop();
    
    return (0);
}


では、関数ごとに分けて説明します。
まずはメイン関数からです。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    init();
    
    glutInit(&__argc, __argv);
    
    glutInitWindowSize(image->width, image->height);
    glutInitDisplayMode(GLUT_RGBA);
    glutCreateWindow("test");
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    
    glutMainLoop();
    
    return (0);
}

まず、メイン関数はmainにするとコンソールウィンドウが出るので、
WinMainを使うことにしました。

上から順に説明すると、initは一番最初に行う処理をする関数です。
実際にしている処理はあとで説明します。

glutInitはOpenGLGLUTを使うときに必要な初期化関数です。
引数にはコマンドライン引数を与えます。

glutInitWindowSizeはウィンドウのサイズを設定する関数です。
一番目の引数にウィンドウの幅を二番目に高さを与えます。

glutInitDisplayMode関数ではディスプレイモードを設定します。
今回は透過ありのカラー画像を表示できるモードになっています。

glutCreateWindowはウィンドウを作成する関数です。
"test"というタイトルでウィンドウを作成しています。

glutDisplayFuncは描画用の関数を設定するための関数です。
drawという関数が描画用の関数になるようにしています。

glutIdleFuncは何もすることがない時に
処理したい関数を設定するための関数です。
idleという関数が描画用の関数になるようにしています。

glutMainLoopは関数名通りメインループを発生させる関数です。


次はinit関数の説明をします。

void init()
{
    // 画像の読み込み
    image = cvLoadImage("image.png", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
    if (image->nChannels >= 2){
        char buf;
        
        for (int i = 0; i < image->width * image->height * image->nChannels;
                i += image->nChannels){
            buf = image->imageData[i];
            image->imageData[i] = image->imageData[i + 2];
            image->imageData[i + 2] = buf;
        }
    }
}

まず、cvLoadImage関数を使い、画像を読み込んでいます。

しかし、この読み込んだ画像はOpenCV仕様になっており、
OpenGLだとRGBのRとBが逆になって表示されてしまうので、
if文内の処理で、RとBの値を入れ替えています。


次は、draw関数の説明です。

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 画像の反転の修正
    glPixelZoom(1, -1);
    // 画像の位置の設定
    glRasterPos2f(-1, 1);
    
    // 画像出力
    switch (image->nChannels){
        case 1:
            // モノクロ画像だった場合
            glDrawPixels(image->width, image->height,
                GL_LUMINANCE, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 3:
            // 透過なしカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGB, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 4:
            // 透過ありカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGBA, GL_UNSIGNED_BYTE, image->imageData);
            break;
    }
    
    glFlush();
}

まず、glClearで画面を初期化します。

次に、今のままだとまだ画像データが
OpenCV仕様のままで、画像が上下反転に表示されてしまいますので、
glPixelZoom関数で修正をしています。

最後にglRasterPos2fで画像の表示位置を設定し、switch文内の
glDrawPixels関数で画像の種類に合わせた方法で表示しています。


次にidle関数ですが、この関数ではglutPostRedisplay関数を使い、
draw関数を呼び出しています。

void idle()
{
    glutPostRedisplay();
}


これで説明は終了です。
お読みくださりありがとうございました。

OpenGLとOpenCVを使って画像を出力する

今回は、OpenGLOpenCVを使って
画像を表示する時のソースを載せます。

今回表示する画像はこれです。
f:id:koreander2001:20140521225751p:plain

今回はコメントつきのソースを載せるので、
説明は次回にしたいと思います。

#include <stdlib.h>
#include <windows.h>

#include <glut.h>

#include <cv.h>
#include <highgui.h>

IplImage *image;

void init()
{
    // 画像の読み込み
    image = cvLoadImage("image.png", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
    if (image->nChannels >= 2){
        char buf;
        
        for (int i = 0; i < image->width * image->height * image->nChannels;
                i += image->nChannels){
            buf = image->imageData[i];
            image->imageData[i] = image->imageData[i + 2];
            image->imageData[i + 2] = buf;
        }
    }
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 画像の反転の修正
    glPixelZoom(1, -1);
    // 画像の位置の設定
    glRasterPos2f(-1, 1);
    
    // 画像出力
    switch (image->nChannels){
        case 1:
            // モノクロ画像だった場合
            glDrawPixels(image->width, image->height,
                GL_LUMINANCE, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 3:
            // 透過なしカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGB, GL_UNSIGNED_BYTE, image->imageData);
            break;
        
        case 4:
            // 透過ありカラー画像の場合
            glDrawPixels(image->width, image->height,
                GL_RGBA, GL_UNSIGNED_BYTE, image->imageData);
            break;
    }
    
    glFlush();
}

void idle()
{
    glutPostRedisplay();
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    init();
    
    glutInit(&__argc, __argv);
    
    glutInitWindowSize(image->width, image->height);
    glutInitDisplayMode(GLUT_RGBA);
    glutCreateWindow("test");
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    
    glutMainLoop();
    
    return (0);
}

ラジオボタンの使い方

前の記事ではRadioButton付きのリストビューの
実装方法について書くと言いましたが、
RadioGroupというクラスを使うと、
リスト上に並んだラジオボタンを一気に管理できるようなので
RadioGroupを使ったソースを書きます。

まずは前回と同じくレイアウトファイルです。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <RadioGroup
        android:id="@+id/radioGroup"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

    </RadioGroup>

</LinearLayout>

内容は殆どリストビューの時と変わっていません。

次はJavaのソースです。

package com.android.testradiobutton;

import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.app.Activity;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // RadioGroup変数の宣言
        RadioGroup radioGroup = (RadioGroup)findViewById(R.id.radioGroup);
        
        // ラジオボタンの作成
        RadioButton radioButton1 = new RadioButton(this);
        radioButton1.setText("One");
        
        RadioButton radioButton2 = new RadioButton(this);
        radioButton2.setText("Two");
        
        RadioButton radioButton3 = new RadioButton(this);
        radioButton3.setText("Three");
        
        // ラジオボタンの登録
        radioGroup.addView(radioButton1);
        radioGroup.addView(radioButton2);
        radioGroup.addView(radioButton3);
    }

}

手順としては、

 ・RadioGroupの変数を宣言する。
 ・登録したい内容のラジオボタンを作成する。
 ・ラジオボタンをRadioGroup変数に登録する。

となっています。

参考サイト
ラジオボタンを作成する: 初心者の初心者のためのAndroidアプリ開発!

Listクラスを使ったリストビューの実装

今回は、Androidアプリ開発でよく使われる
リストビューをJavaのListクラスを使って
実装する為のソースを書きます。

まず、リストビューを使う場合の
レイアウトファイルを書いておきます。

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <ListView
        android:id="@+id/listView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

次はJavaファイルです。

MainActivity.java

package com.android.testlist;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // ListView変数の宣言
        ListView listView = (ListView)findViewById(R.id.listView);
        
        // List変数の宣言
        List<String> list = new ArrayList<String>();
        
        // List変数への要素の追加
        list.add("One");
        list.add("Two");
        list.add("Three");
        
        // ListをセットしたArrayAdapter変数の宣言
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
        
        // リストビューにArrayAdapter変数をセット
        listView.setAdapter(adapter);
    }

}

リストビューをListクラスを使って実装する場合、
手順は以下の通りになります。

・ListViewの変数を宣言する。
・Listの変数を宣言し、必要な要素を追加する。
・List変数がセットされたArrayAdapter変数を宣言する。
・宣言したArrayAdapter変数をリストビューにセットする。

どの部分がどこについて書いているかは
コメントを参照してください。

今回の記事はこれで終了です。
次回はラジオボタン付きのリストビューの実装
について書きます。


参考サイト
Android リストビュー(ListView)を使う | Tech Booster

「力学の書」中止のお知らせ

昨日始めたばかりの「力学の書」ですが、
この記事は、私自身が力学を始めていくうえで
学んだ内容をまとめていくために書こうとした記事でした。

しかし、はてなブログでは分数を表現できないみたいです。
私が方法を知らないだけかもしれませんが。

力学についてまとめるうえで
分数の表現が1/2のように'/'を使う方法しかないのは
ただでさえ読みづらい私の記事が
さらに冗長かつ見づらいものになってしまうかと思います。

ですので、突然ではありますが、
この記事は私が分数を表現できる方法を見つける、
若しくは分数を使わずとも力学について
まとめる事ができるようになるまで
停止することにいたします。

始めたばかりの記事にもかかわらず
突然停止してしまい申し訳ありませんでした。

力学の書1 はじめに

1.この記事での「力学」について

「力学」というものに対してこの記事を書くにあたって、
まず、この記事の中での「力学」とは何かを決めたいと思います。

最も広い意味で「力学」というと、
力そのものとその力が他の力に対してどのような影響を与えるか、
力が物体に対して与える影響など、かなり広い範囲の話になって
しまいます。

ですので、この記事の中では、「力学」は、
ニュートン力学と呼ばれるかつてニュートンがまとめた
ニュートンの運動の法則を基にして導かれた部分のみのことを
言うことにします。


2.ニュートンの運動の法則とは

ニュートンの運動の法則を基にした部分をまとめると書いたので、
今回は、法則自体を記したいと思います。

ニュートンの運動の法則は次の3つの法則の事をいいます。


第一の法則・慣性の法則

 物体は、外から力が加わらない場合、等速直線運動を続ける。


第二の法則・運動の法則

 物体に力が働いた場合、力によって生じた加速度は、
 力の大きさに比例し、物体の質量に反比例する。
 その物体に働いた力をF、物体の質量をm、
 力によって生じた加速度をaとしたとき、次の式が成り立つ。
 
  F = ma


第三の法則・作用・反作用の法則

 物体が別の物体に力を加える(作用する)とき、
 力を加えた側の物体には、加えられた側の物体から
 同じ大きさで逆向きの力が必ず加わる。


参考文献

講談社基礎物理学シリーズ1・力学
著/副島雄児・杉山忠男

BCC DeveloperでOpenCVを使う方法

今回は、自分でやろうと思った時に
思っていたよりも面倒だったので
BCC DeveloperでOpenCVを使いたいときの方法を
まとめます。

*動作確認はWindows7のみでしかしていません。


1.ダウンロード

まずはダウンロードです。

ここの"opencv-win"→"1.0"→"OpenCV_1.0.exe"をダウンロードしてください。


2.インストール

ダウンロードしたファイルを実行してインストールしてください。

途中でインストール先のフォルダを選ぶところがありますが、
デフォルトの"C:Program Files\OpenCV"ではなく、
"C:\OpenCV"を選んでください。


3.使用前の準備

現在インストールしたファイルはBCCに対応していませんので、
使用する前にBCCでも動かせるようにしましょう。

まず、"C:\OpenCV"内にBCCで使えるファイルを
入れるためのフォルダ(私は"lib_bcc"としました)を作りましょう。

次にコマンドプロンプトを起動し、
"cd C:\OpenCV"と打ってください。
その後、"C:\OpenCV\lib"フォルダ内の全てのファイルに対し、
"coff2omf lib\ファイル名 lib_bcc\同じファイル名"
というコマンドを実行してください。

これでひとまずファイル自体はBCCに対応できました。

しかし、まだBCC Developer側の設定をしていませんので、
次は設定をします。

まずは"C:\borland\bcc55\Bin\bcc32.cfg"というファイルを
開いてください。

既に中に

-I"C:\borland\bcc55\include"
-L"C:\borland\bcc55\lib"

と打たれているかと思います。

この下に、

-I"C:\OpenCV\cv\include"
-I"C:\OpenCV\cxcore\include"
-I"C:\OpenCV\otherlibs\highgui"
-L"C:\OpenCV\lib_bcc"

と追記してください。

次に"C:\borland\bcc55\Bin\ilink32.cfg"というファイルの中を

-L"C:\borland\bcc55\lib"
-L"C:\OpenCV\lib_bcc"

と書き換えてください。


次は、環境変数というものを設定します。

まず、スタートメニュー内の"コンピュータ"を右クリックし、
"プロパティ(R)"をクリックしてください。

すると、
f:id:koreander2001:20140521204900p:plain
のようなウィンドウが出来ると思います。

このウィンドウの"システムの詳細設定"をクリックしてください。
f:id:koreander2001:20140521204902p:plain

今度は、
f:id:koreander2001:20140516225038p:plain
のようなウィンドウが開くと思います。

このウィンドウの"環境変数"をクリックしてください。
f:id:koreander2001:20140516225437p:plain

次は、下のウィンドウが開くので、"Path"を選択して
"編集"をクリックしてください。
f:id:koreander2001:20140516225721p:plain

またウィンドウが出てくるので、ウィンドウ内の
"変数値"の終端に";C:\OpenCV\bin"と追記してください。
f:id:koreander2001:20140516230204p:plain

これで環境変数の設定は終了です。

最後に、BCC Developerを起動し、
メニューの"プロジェクト"内の"デフォルトプロジェクトの編集"
をクリックしてください。
f:id:koreander2001:20140516225040p:plain

出てきたウィンドウの"リンク"タブで
"C:OpenCV\lib_bcc\cv.lib"
"C:OpenCV\lib_bcc\cxcore.lib"
"C:OpenCV\lib_bcc\highgui.lib"
を追加してください。
f:id:koreander2001:20140516225041p:plain

これで、"cv.h"と"highgui.h"をインクルードすれば
OpenCVを使えるようになりました。

参考サイト
™'s Borland C++ Compiler Environment ™œc