【Delphi】「表示中のウィンドウをモーダルに出来ません」エラーへの対応

フォームを動的に表示するアプリケーションを作っている際に理不尽なエラーが起こったのでメモ.

procedure TFormUndistortionTool.ButtonUndistortExecuteClick(Sender: TObject);
    var
        aForm : TFormUndistortionParameter;
    begin
    aForm := TFormUndistortionParameter.Create( Self );
    try
        aForm.ShowModal;
    finally
        FreeAndNIL( aForm );
        end;
    end;

こんな感じに,ボタンをクリック時にフォームを表示するコードを実行すると,下図のエラーが発生.

f:id:melank:20141023234938p:plain

ひと通り悩んで,表示しようとしていたフォームの Visibleプロパティが True となっていたことが原因っぽいことが判明.Visibleが有効なので,すでに表示中であるという判定がなされているよう.そこで,プロパティパネルで初期値は False とし,OnFormShowイベント時に True に変更するように指定すると,無事表示したフォームが開けた.但し,フォームだけ表示を有効にしても,中のコンポーネントは表示されないので下図のようなのっぺらぼうなフォームが出来てしまう.

f:id:melank:20141023235743p:plain

procedure TFormUndistortionParameter.FormShow(Sender: TObject);
    var
        i : Integer;
    begin
    for i := 0 to ComponentCount - 1 do
        ( Components[i] as TControl ).Visible := True;
    end;

こんな感じにフォーム上のコンポーネントの表示を一斉に有効にして,対応した.フレームワークで作る際はこんな面倒くさい処理を挟まなくても,問題なく作れたんだけど,ちょっとスクラッチで書こうとすると色々問題が出てくる.たいへん.

【XCode】Mac OSX 10.9 でも GLUTを非警告で使う

Mac OSX 10.9 以降から,OpenGL 1.x系,GLUT系関数使用時に警告を出すようになった.XCode上では非推奨という扱いになったとしても,私的にはリファレンスのいっぱいあるやつを使っていたい.ので,警告を取る方法を探してみた.

f:id:melank:20140520204241p:plain

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

警告を非表示にする方法は,Visual Studio とほぼ同じで #Pragma指令に,警告ごとに用意されている定数を指定するだけ.これで鬱陶しいメッセージは非表示になりました.

今回はあまりの違和感に有無を言わさず非表示にしてみたけれど,IOSにDeprecated(廃止予定)って扱われるくらいだから,なにか他のものに乗り換えたほうが良いのかなー.最近は,Delphiしかやってないから全く分かんない.C++全くわかりません


2014/05/29 追記

未使用の変数・関数を Unused警告出してくるのも鬱陶しく,こちらも非表示できたのでその方法をメモ.
プロジェクトの設定から「Build Settings」タブを開き,「Unused Function」と「Unused Variables」をNoにすると,未使用の関数・変数があった場合の Warning を非表示に出来るようです.今回はDebug時のみ「No」とするようにしました.

f:id:melank:20140530003011p:plain

Ovrvision - 映像表示

先週,Oculus Rift用のステレオカメラである,Ovrvisionが手元に届いたので,映像を表示するだけの最低限のプログラムを書いてみました.

環境は,VisualStudio2010, C++版OvrvisionSDK, OpenCV2.4 です.

#include <iostream>
#include <opencv2¥opencv.hpp>
#include <ovrvision.h>
using namespace System;

const int  windows_pos[2]      = {200, 200};
const char left_window_name[]  = "OVRVISION_LEFT";
const char right_window_name[] = "OVRVISION_RIGHT";

OVR::Ovrvision* g_ovr;

int main(array <String ^> ^args)
{
    g_ovr = new OVR::Ovrvision();
    
    if ( g_ovr->Open(0, OVR::OV_CAMVGA_FULL) != 0 ){
        cout << "Failed to detect ovrvision camera..." ;
        exit(-1);
    }
    cv::namedWindow( left_window_name, CV_WINDOW_AUTOSIZE );
    cv::namedWindow( right_window_name, CV_WINDOW_AUTOSIZE );
    
     // Display
    while(1) {
        cv::Mat l_image( 480, 640, CV_8UC3 ), r_image( 480, 640, CV_8UC3 );
        cv::Mat l_image_buf( 480, 640, CV_8UC3 ), r_image_buf( 480, 640, CV_8UC3 );
        
        // Get pixel data. 640*480*3Byte
        //g_ovr->GetCamImage( l_image.data, OVR::OV_CAMEYE_LEFT );
        //g_ovr->GetCamImage( r_image.data, OVR::OV_CAMEYE_RIGHT );
        g_ovr->GetCamImage( l_image_buf.data, OVR::OV_CAMEYE_LEFT );
        g_ovr->GetCamImage( r_image_buf.data, OVR::OV_CAMEYE_RIGHT );
        
        // Undistortion
        g_ovr->ImageUndistort( l_image.data, l_image_buf.data );
        g_ovr->ImageUndistort( r_image.data, r_image_buf.data );
        
        cv::cvtColor( l_image, l_image,  CV_RGB2BGR );
        cv::cvtColor( r_image, r_image, CV_RGB2BGR );
        
        // draw                    
        cv::imshow( left_window_name, l_image );
        cv::moveWindow( left_window_name, windows_pos[0], windows_pos[1] );
        cv::imshow( right_window_name, r_image );
        cv::moveWindow( right_window_name, windows_pos[0] + g_ovr->GetImageWidth() + 8, windows_pos[1] );
        
        if( cv::waitKey(27) >= 0 ) break ;
        // cout << g_ovr->GetImageRate() << endl;
    }
    
    g_ovr->Close();    
    delete g_ovr;
    cv::destroyWindow(left_window_name);
    cv::destroyWindow(right_window_name);
    
    return 0;
}

f:id:melank:20140402003114p:plain

取り敢えずキャプチャしたものが上図.並べてはみたけど,ウィンドウ枠の除去が OpenCVの標準じゃ出来ないみたいなので,表示の方法は変えないといけなさそう.

現状,SDKとして提供されているのは,カメラ画像の取得,魚眼レンズの樽ひずみの補正,各パラメータ用のアクセッサのみで,Oculus使ってARが出来るよって押し出してた割には,公式だけではまだあまり何かが出来る状況ではないような印象.無料でARやるなら,Vuforiaライブラリとか使うことになるのかなー.

14/04/19 追記
4月頭にはAR用の機能をまとめた OvrvisionEx Class が追加されていたようです.SDK単体でマーカ検出ができるようになりました.

pygame-1 ウィンドウ生成と画像表示

基本的なウィンドウの生成方法

# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys

SCREEN_SIZE = (720, 480)

pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Pygame Test")
background = pygame.image.load("Hitagisama.jpg").convert()

while True:
    screen.fill((0, 0, 0))
    screen.blit(background, (0, 0))
    pygame.display.update()

    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if KEYDOWN == K_ESCAPE:
            sys.exit()

pygameでは,19行でウィンドウの生成と画像の表示を行えます.

# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys

ウィンドウを生成するのに必要なモジュールは,基本的には pygame のみですが,pygameで定義されている定数を使用するため,pygame.localsモジュールを,アプリケーションを終了するイベントを呼ぶために sysモジュールをインポートしておきます.

pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Pygame Test")
background = pygame.image.load("Hitagisama.jpg").convert()

init では名前の通り,読み込まれているすべてのモジュールを初期化します.

次にウィンドウの各設定です.display.set_mode で表示するウィンドウの初期化を行います.フラグを渡すことで,全画面やリサイズ可能と言ったオプションを指定できますが,今回は解像度だけを渡します.

最後に画像の読み込みです.image.loadの引数に画像へのpathを渡すことで読み込む画像の指定を行い,convert()で,ピクセル形式を指定します.ピクセル形式は,画像を表示する部分( surface )が読み込んだ画像のピクセルの色をどのように記録するかを設定するものです,読み込んだ画像の中身に手を加えない場合,はじめに一度設定しておくと何度もconvertが呼ばれる様な無駄な処理を省けます.

while True:
    screen.fill((0, 0, 0))
    screen.blit(background, (0, 0))
    pygame.display.update()

    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if KEYDOWN == K_ESCAPE:
            sys.exit()

fill では,描画部分の色を指定します.ウィンドウの設定同様に,他に引数を渡すことで特定部位の色指定やアルファブレンディングなどのオプションを指定することもできますが,今回はウィンドウの背景色だけを指定します.

blitは読み込んだ画像を実際に表示するために,surfaceにビットマップ転送を行います.要するに読み込んだ画像のピクセル色を格納した配列を描画部分にコピーする処理です.これを呼ぶことで,実際にウィンドウに画像を表示します.

display.updateは,画面の更新です.デフォルト引数でNoneが渡されていますが,rectという句形データを渡すことで部分的な更新を指示できるので,画面全体を更新する無駄を省くことができます.

最後にevent.get() でイベントキューからイベントの取得を行います.キーイベントやマウスイベントなどを,定義されている定数を用いて取得します,