ファイラーその1

WPFのデータバインディング等が思ったより難解でちっともペースが上がらない。
手の込んだものを作るのは無理そうなので、
listboxの練習にfiler的なものを作ってみる。

FileView.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;

namespace filer
{
    // DataContextに使う
    class FileView : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private DirectoryInfo current_;
        // TextBox.Textにバインドする
        public String Path
        {
            get { return current_.FullName; }
            set
            {
                current_ = new DirectoryInfo(value);
                NotifyPropertyChanged("Path");
                files_ = new ObservableCollection<FileSystemInfo>(
                current_.GetFileSystemInfos().ToArray());
            }
        }

        private ObservableCollection<FileSystemInfo> files_ = new ObservableCollection<FileSystemInfo>();
        // ListBox.ItemsSouceにバインドする
        public ReadOnlyObservableCollection<FileSystemInfo> Files
        {
            get { return new ReadOnlyObservableCollection<FileSystemInfo>(files_); }
        }

        public FileView(String path)
        {
            Path = path;
        }
    }
}

MainWindow.xaml

<Window x:Class="filer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:IO="clr-namespace:System.IO;assembly=mscorlib"
        Title="Filer" Height="350" Width="525">
    <Window.Resources>
        <!-- Directory向け -->
        <DataTemplate DataType="{x:Type IO:DirectoryInfo}">
            <Label Content="{Binding Path=Name}"  Foreground="#FF2222"/>
        </DataTemplate>
        <!-- File向け -->
        <DataTemplate DataType="{x:Type IO:FileInfo}">
            <StackPanel Orientation="Horizontal">
                <Label Width="100" Content="{Binding Path=Name}"/>
                <Label Width="100" Content="{Binding Path=Length}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Name="currentFolder" Text="{Binding Path=Path}" />
        <ScrollViewer Grid.Row="1" >
            <ListBox Name="currentFolderFiles" ItemsSource="{Binding Path=Files}">
<!-- Resourcesで定義したDataTypeつきのDataTemplateが自動的に選択される -->
            </ListBox>
        </ScrollViewer>
    </Grid>
</Window>

DataTemplateのDataTypeを利用してlistboxのitemの種類に応じて、動的に適用するDataTemplateを変える手法を使っている。
この方法を使うには、DataTemplateをResoucesに配置することが必要。

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace filer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext=new FileView("C:\\");
        }
    }
}

WPFことはじめ

WPFをはじめてみた。
いくつかwpfの記事や書籍を見たのだが小さく始まるお手軽なチュートリアルが無くて、
わりと学習曲線が急に感じられる(抽象から入る説明が苦手w)。
どうやら、WPFはWindowsFormsのようにWin32apiをラップしたものでは無くてDirectXの上に再構築したGUIらしい。
調べていくとこれが意外とよさげで、現時点のWindowsGUIではベストな選択のような気がしてきた。
その代わりに最初に飲み込むべき概念がちょっと多いようだ。
メモしながら整理することにした。


まずは、ツリービューから。


モデル(追加 -> 新規クラス -> Node.cs)

namespace Sample
{
    class Node
    {
        // プロパティじゃないとBindingできない
        private List<Node> children_ = new List<Node>();
        public List<Node> Children
        {
            get { return children_; }
        }

        // プロパティじゃないとBindingできない
        public string Name
        {
            get;
            set;
        }

        public Node(string name)
        {
            Name = name;
        }

        public Node AddChild(Node node)
        {
            children_.Add(node);
            return node;
        }
    }
}

ビュー(MainWindow.xaml)

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView Width="200" Height="200" ItemsSource="{Binding Path=Children}"><!-- DataContext.Childrenの意らしい -->
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}"><!-- 再帰的。ChildrenのChildren  -->
                    <TextBlock Text="{Binding Path=Name}"/><!-- ノード一個分。Node.Name -->
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

ビューがモデルを参照する(MainWindow.xaml.cs)

namespace Sample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var tree=new Node("root");
            var node1=tree.AddChild(new Node("node1"));
            var node1_1 = node1.AddChild(new Node("node1_1"));
            var node1_2 = node1.AddChild(new Node("node1_2"));

            // ビューはDataContextを通してBindingする
            DataContext = tree;
        }
    }
}

実行してみた。"root"より下の階層が表示された。
rootのChildrenのChildrenから表示される。

モデルの更新通知を導入する

まず、モデルを更新するボタンを追加する

        <Button Height="23" HorizontalAlignment="Left" Margin="152,262,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click">
            AddNode
        </Button>
namespace Sample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private Node root_;

        public MainWindow()
        {
            InitializeComponent();

            // 変更できるようにメンバ変数にとっておく
            root_=new Node("root");
            var node1=root_.AddChild(new Node("node1"));
            var node1_1 = node1.AddChild(new Node("node1_1"));
            var node1_2 = node1.AddChild(new Node("node1_2"));

            DataContext = root_;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            // モデルを更新
            root_.AddChild(new Node("AddNode"));
        }
    }
}

ボタンを押しても画面は変化しない。

ListをObservableCollectionに置換する。

using System.Collections.ObjectModel;

namespace Sample
{
    class Node
    {
        // プロパティじゃないとBindingできない
        private ObservableCollection<Node> children_ = new ObservableCollection<Node>();
        public ObservableCollection<Node> Children
        {
            get { return children_; }
        }

// 省略

     }
}

ボタンを押すとノードが追加されるようになった。

macbook airにgentoo linuxをインストールする

gentoo-3.3.8

その1

  • OSXで領域を縮小する(30GB)にした
  • OSXでrEFItをインストールする

その2

gentooのinstall環境としてubuntuのbootable usbメモリを作る。

その3

ubuntuusbメモリから起動して、
handbookを見てインストールを進める

fdisk
1 /dev/sda1 boot EFI領域 # 温存
2 /dev/sda2 HFS+ OSX # 温存
3 /dev/sda3 swap 1G
4 /dev/sda4 ext4 残り全部 
必要なカーネルオプション

素の状態からmake menuconfigしたものから変更した部分のメモ

General
  .config

Processor
  core2

FileSystem
  ext4
  fuse
  dos
    codepage 932
    charset utf8
    NTFS
  Network
    CIFS # samba
  Miscellaneous
    HFS+

Device
  NetWork
    Wireless
      80211 # 後でブロードコムの内臓無線ドライバをビルドするのに必要
    USB
      asix # 外付けのUSB-ether

  USB
    roothub transaction # タッチパッドの認識に必要 http://forums.gentoo.org/viewtopic-t-878287-start-0.html

  InputDevice
    Mice
      BCM5974 # タッチパッド

  Graphics
    agp
      Intel440
    DRM

  Sound
    alsa
      pci
        Intel HD # カーネル組み込みからモジュールに変更した
broadcomのドライバをビルドしてインストールする

その4

grub2をefiサポートでビルドする

--disable-werror
--disable-nls

起動成功

その5 ネットワーク設定

wpa_supplicant

コミットのユーザ名を修正する

こちらに書いてあった
http://d.hatena.ne.jp/idesaku/20090908/1252419890

set -x

git filter-branch --commit-filter '
GIT_AUTHOR_NAME="ousttrue"
GIT_AUTHOR_EMAIL="ousttrue@gmail.com"
GIT_COMMITER_NAME="ousttrue"
GIT_COMMITER_EMAIL="ousttrue@gmail.com"
git commit-tree "$@"
' HEAD^^^..HEAD

# HEAD^^ HEAD^ HEADが対象(HEAD^^^は入らない)

DirectShowを入力として、OpenCVで画像処理して、DirectXでテクスチャとして表示するサンプル

を作った。
https://github.com/ousttrue/dscvd3d

とりあえずOpenCVの画像処理にはカメラキャリブレーションとその補正をやってみたのだけど、歪んでない画像が補正したことによりより歪んでしまう状態になってしまった。使い方が間違っているのかもしれない。

メモ

rgbaの配列をOpenCVで処理して、書き戻すメモ。
メモリを新しく確保しているところが無駄だがとりあえず。

#include <opencv2/core/core.hpp>

void Process(unsigned char *data, int w, int h)
{
  // 8bit Unsigned 4Channel
    cv::Mat image(h, w, CV_8UC4);

    // input
    memcpy(&image.at<cv::Vec4b>(0, 0), data, w*h*4);

    // 処理ネガポジ反転
    image = ~image;

    // output
    memcpy(data, &image.at<cv::Vec4b>(0, 0), w*h*4);
}

↑はだめな方法。
下記のようにできた。

    cv::Mat image(h, w, CV_8UC4, data);
    // 処理
    image = ~image;

USBカメラを静止画で取得する(サンプルグラバ)

DirectXのテクスチャにDirectShowを出力する方法を試してみた。
最初に、

を参考にしたのだが、

strmbase.lib(strmbasd.lib)をVC2010でビルドするのに失敗して
コンパイルを通すことがそもそもできなかったorz

仕方ないのでDirectShow基本ライブラリに含まれるCBaseVideoRendererを使うのはおいておいて、SampleGrabberを使う手法をやってみた。

SampleGrabberを使う

こちらを参考にした。

qedit.hが無い

VC2010とは別にインストールした古いWindowsSDKに含まれていた

C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\qedit.h

昔のDirectX(DirectShowが含まれているやつ)でもいいらしい

dxtrans.hが無い

C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\qedit.h

を直接修正するらしい

ようやく実装開始

DirectShowは含まれるライブラリが転々としているせいで、どこにインクルードやリンクがあるのか探すので苦労する・・・
入力と出力を持つフィルタを作って、これらをグラフに追加して連結する仕組みだとわかった。
ということで、出力を持つUSBカメラフィルタと入力をもつサンプルグラバを連結した。

ComMovie.h

#pragma once
#include <atlbase.h>
#include <dshow.h>
#include <qedit.h>
#pragma comment(lib, "strmiids")
#include <vector>


class Com
{
public:
    Com()
    {
        CoInitialize(NULL);
    }

    ~Com()
    {
        CoUninitialize();
    }
};


class ComMovieSource
{
    Com m_com;

    CComPtr<IGraphBuilder> m_graphBuilder;
    CComQIPtr<IMediaControl> m_mediaControl;

    CComPtr<ICaptureGraphBuilder2> m_captureGraphBulider;

    // 出力
    CComPtr<IBaseFilter> m_sampleGrabberFilter;
    CComQIPtr<ISampleGrabber> m_sampleGrabber;

    // 入力
    CComPtr<IBaseFilter> m_deviceFilter;

    int m_w;
    int m_h;

    std::vector<BYTE> m_buffer;

public:
    ComMovieSource();
    ~ComMovieSource();
    HRESULT Initialize();
    int GetWidth(){ return m_w; }
    int GetHeight(){ return m_h; }
    HRESULT Update();
    void *GetSample(){ return m_buffer.empty() ? 0 : &m_buffer[0]; }
    size_t GetSampleSize(){ return m_buffer.size(); }
};

ComMovie.cpp

#include "ComMovie.h"


ComMovieSource::ComMovieSource()
    : m_w(0), m_h(0)
{
}

ComMovieSource::~ComMovieSource()
{
}

HRESULT ComMovieSource::Initialize()
{
    if(m_graphBuilder){
        return S_OK;
    }

    // filter graph
    if (FAILED(m_graphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC))){
        return E_FAIL;
    }

    // add sample grabber
    if(FAILED(m_sampleGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC))){
        return E_FAIL;
    }

    m_sampleGrabberFilter.QueryInterface(&m_sampleGrabber);
    if(!m_sampleGrabber){
        return E_FAIL;
    }

    AM_MEDIA_TYPE amt;
    ZeroMemory(&amt, sizeof(amt));
    amt.majortype  = MEDIATYPE_Video;
    amt.subtype	   = MEDIASUBTYPE_RGB32;
    amt.formattype = FORMAT_VideoInfo; 
    m_sampleGrabber->SetMediaType(&amt);
    if(FAILED(m_graphBuilder->AddFilter(m_sampleGrabberFilter, L"Sample Grabber"))){
        return E_FAIL;
    }

    // add capture filter
    if(FAILED(m_captureGraphBulider.CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC))){
        return E_FAIL;
    }
    if(FAILED(m_captureGraphBulider->SetFiltergraph(m_graphBuilder))){
        return E_FAIL;
    }

    // デバイスを列挙するためのCreateDevEnumを生成
    CComPtr<ICreateDevEnum> createDevEnum;
    if(FAILED(createDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER))){
        return E_FAIL;
    }
    CComPtr<IEnumMoniker> enumMoniker;
    createDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumMoniker, 0);
    if(!enumMoniker){
        // no device
        return E_FAIL;
    }
    enumMoniker->Reset();
    while(true){
        CComPtr<IMoniker> moniker ;
        DWORD nFetched;
        if(FAILED(enumMoniker->Next(1, &moniker, &nFetched))){
            return E_FAIL;
        }
        if(nFetched<1){
            break;
        }

        // ToDo: 条件に合うデバイスをバインドする
        {
            // 一個目のUSBカメラ
            moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_deviceFilter);
            break;
        }
    }

    if(FAILED(m_graphBuilder->AddFilter(m_deviceFilter, L"Video Input Device"))){
        return E_FAIL;
    }

    // デバイスとグラバフィルタを連結する
    if(FAILED(m_captureGraphBulider->RenderStream(&PIN_CATEGORY_PREVIEW,
                    NULL, m_deviceFilter, NULL, m_sampleGrabberFilter))){
        return E_FAIL;
    }

    // 画像サイズ
    if(FAILED(m_sampleGrabber->GetConnectedMediaType(&amt))){
        return E_FAIL;
    }
    VIDEOINFOHEADER *pVideoInfoHeader =
        (VIDEOINFOHEADER *)amt.pbFormat;

    m_w=pVideoInfoHeader->bmiHeader.biWidth;
    m_h=pVideoInfoHeader->bmiHeader.biHeight;
    m_buffer.resize(amt.lSampleSize);

    // 開始
    m_sampleGrabber->SetBufferSamples(TRUE);
    m_graphBuilder.QueryInterface(&m_mediaControl);
    if(!m_mediaControl){
        return E_FAIL;
    }
    if(FAILED(m_mediaControl->Run())){
        return E_FAIL;
    }

    return S_OK;
}

HRESULT ComMovieSource::Update()
{
    if(m_buffer.empty()){
        return E_FAIL;
    }
    // 現在表示されている映像を静止画として取得
    long nBufferSize=m_buffer.size();
    HRESULT hr=m_sampleGrabber->GetCurrentBuffer(&nBufferSize, (long*)&m_buffer[0]);
    if(SUCCEEDED(hr) && nBufferSize==m_buffer.size()){
        return S_OK;
    }
    return E_FAIL;
}