ともさんのHP >プロブラミング >USBカメラをJAVAで制御して定点観測 >定点観測カメラソフトの作成

定点観測カメラソフトの作成

JAVAを使って、定点観測カメラのソフトウエアを作ります。
構想はこちら

JAVAプログラムの処理内容

ソフトにやってもらう仕事は下記の通りですが、今回は1,2,3の作業を行うプログラムを作ります。
1 10分ごとに同じ場所を撮影
2 画像を6×8ピクセルの大きさに縮小する
3 画像データを一旦データベースに入れる
4 ある程度溜まったら、データを取り出し、
  大きな画像上に小さな画像を順番に並べてゆく。
5 完成したモザイク画像をNET上にUPする。


10分ごとに処理を実行するJAVAプログラム

まずは10分に1回処理を実行するプログラムを作ってみました。 単純に10分に1回ではなくて、毎時0,10,20,30,40,50分に1回処理を実行するようにしてみました。
下のソースを実行すると、時刻になったら、現在時刻を表示します。


package tomojavalib.usbcamera;

import java.util.Calendar;


public class IntTakePic implements Runnable
{
    //変数の定義
    Thread timer;
    boolean flug1 = false; //前回調査した分が0,10,20,30,40,50であるか
    boolean flug2 = false; //今回調査した分が0,10,20,30,40,50であるか
    
    public static void main(String args[]) throws Exception 
    {
         IntTakePic i = new IntTakePic();
    }
    
    public IntTakePic()
    {
          //タイマースタート
          timer = new Thread(this);
          timer.start();
    }
    
    public void run()
    {
         //無限ループ
          do{
           //10秒休憩
           try{ timer.sleep(10000);}catch(InterruptedException e){}
           check();
          }while(true);
    }

    /**
     * 現在の時刻を調べ、0,10,20,30,40,50分になったばかりであればtake()の処理を実行
     */
    public void check()
    {
         Calendar c = Calendar.getInstance();     //一時使用カレンダの作成
          tomojavalib.util.Jikoku j = new tomojavalib.util.Jikoku();
          String jikoku = j.stringNow() ;
         int min = c.get(Calendar.MINUTE);
         flug2 = false;
         if(min==0){flug2 = true;} else if(min==10){flug2 = true;} else if(min==10){flug2 = true;} else if(min==30){flug2 = true;}
         else if(min==40){flug2 = true;} else if(min==50){flug2 = true;}
         if( flug1 == false ){ if( flug2 ==true ){ takePic( jikoku ); } }
         flug1 = false;
         if(min==0){flug1 = true;} else if(min==10){flug1 = true;} else if(min==10){flug1 = true;} else if(min==30){flug1 = true;}
         else if(min==40){flug1 = true;} else if(min==50){flug1 = true;}          
    }
    /**
     * 画像の撮影
     * @param jikoku :現在時刻
     */
    public void takePic( String jikoku )
    {
         System.out.println( "現在の時刻 " + jikoku + flug1 + flug2);
    }

}


JAVAでUSBカメラを使うための準備

撮影する前にUSB カメラ 楽天 を起動させましょう。
赤字の部分を追記すると、ウインドウが開いて、 UBSカメラ 楽天 の撮影している画像が写ります。
このプログラムはWindowsしか動きません。また、JMFをインストールしている必要があります。
JAVA 楽天  JMF)で検索してみてください。
別にウインドウが開かなくても問題ないのですが、あったほうが良いでしょうってことで。

広告


package tomojavalib.usbcamera;

import java.awt.Image;
import java.util.Calendar;

import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.swing.JFrame;


public class IntTakePic implements Runnable
{
    //変数の定義
    Thread timer;
    boolean flug1 = false; //前回調査した分が0,10,20,30,40,50であるか
    boolean flug2 = false; //今回調査した分が0,10,20,30,40,50であるか
    JFrame frame =null;
    Player player = null;
    
    public static void main(String args[]) throws Exception 
    {
         IntTakePic i = new IntTakePic();
    }
    
    public IntTakePic()
    {
         //usbカメラを動かす
          startCamera();
          //タイマースタート
          timer = new Thread(this);
          timer.start();
    }
    
    public void run()
    {
         //無限ループ
          do{
           //10秒休憩
           try{ timer.sleep(10000);}catch(InterruptedException e){}
           check();
          }while(true);
    }

    /**
     * 現在の時刻を調べ、0,10,20,30,40,50分になったばかりであればtake()の処理を実行
     */
    public void check()
    {
         Calendar c = Calendar.getInstance();     //一時使用カレンダの作成
          tomojavalib.util.Jikoku j = new tomojavalib.util.Jikoku();
          String jikoku = j.stringNow() ;
         int min = c.get(Calendar.MINUTE);
         flug2 = false;
         if(min==0){flug2 = true;} else if(min==10){flug2 = true;} else if(min==10){flug2 = true;} else if(min==30){flug2 = true;}
         else if(min==40){flug2 = true;} else if(min==50){flug2 = true;}
         if( flug1 == false ){ if( flug2 ==true ){ takePic( jikoku ); } }
         flug1 = false;
         if(min==0){flug1 = true;} else if(min==10){flug1 = true;} else if(min==10){flug1 = true;} else if(min==30){flug1 = true;}
         else if(min==40){flug1 = true;} else if(min==50){flug1 = true;}          
    }
    /**
     * 画像の撮影
     * @param jikoku :現在時刻
     */
    public void takePic( String jikoku )
    {
         System.out.println( "現在の時刻 " + jikoku + flug1 + flug2);
    }

    public void startCamera()
    {
         //USBカメラとの接続
         try{
        frame = new JFrame("USB-Camera");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        player = Manager.createRealizedPlayer(new MediaLocator("vfw://0"));
        frame.setBounds(50, 50, 640, 480);
        frame.getContentPane().add(player.getVisualComponent());
        frame.setVisible(true);
        player.start();
         }catch(Exception e){};
    }     
    
}



JAVAでUSBカメラから取り込んだ画像をJPGファイルに保存

では、10分ごとにUSBカメラの画像をファイルに保存するようにしましょう。
これも赤字の部分を追記します。
これで10分ごとに撮影時刻のファイル名で画像が保存されるようになりました。


package tomojavalib.usbcamera;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Calendar;

import javax.media.Buffer;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.JFrame;


public class IntTakePic implements Runnable
{
    //変数の定義
    Thread timer;
    boolean flug1 = false; //前回調査した分が0,10,20,30,40,50であるか
    boolean flug2 = false; //今回調査した分が0,10,20,30,40,50であるか
    Image img = null;
    java.awt.image.BufferedImage ssimg = null;
    JFrame frame =null;
    Player player = null;
    
    public static void main(String args[]) throws Exception 
    {
         IntTakePic i = new IntTakePic();
    }
    
    public IntTakePic()
    {
         //usbカメラを動かす
          startCamera();
          //タイマースタート
          timer = new Thread(this);
          timer.start();
    }
    
    public void run()
    {
         //無限ループ
          do{
           //10秒休憩
           try{ timer.sleep(1000);}catch(InterruptedException e){}
           check();
          }while(true);
    }

    /**
     * 現在の時刻を調べ、0,10,20,30,40,50分になったばかりであればtake()の処理を実行
     */
    public void check()
    {
         Calendar c = Calendar.getInstance();     //一時使用カレンダの作成
          tomojavalib.util.Jikoku j = new tomojavalib.util.Jikoku();
          String jikoku = j.stringNow() ;
         int min = c.get(Calendar.MINUTE);
         flug2 = false;
         if(min==0){flug2 = true;} else if(min==10){flug2 = true;} else if(min==10){flug2 = true;} else if(min==30){flug2 = true;}
         else if(min==40){flug2 = true;} else if(min==50){flug2 = true;}
         if( flug1 == false ){ if( flug2 ==true ){ takePic( jikoku ); } }
         flug1 = false;
         if(min==0){flug1 = true;} else if(min==10){flug1 = true;} else if(min==10){flug1 = true;} else if(min==30){flug1 = true;}
         else if(min==40){flug1 = true;} else if(min==50){flug1 = true;}          
    }
    
    
    /**
     * 画像の撮影
     * @param jikoku :現在時刻
     */
    public void takePic( String jikoku )
    {
         //画像をバファードイメージに入れる
        FrameGrabbingControl frameGrabber  = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
        Buffer buf = frameGrabber.grabFrame();
        BufferToImage b2i = new BufferToImage((VideoFormat) buf.getFormat());
        img = b2i.createImage(buf);
        ssimg = new java.awt.image.BufferedImage( 640, 480 ,java.awt.image.BufferedImage.TYPE_INT_RGB  );
         Graphics g = null;
        g = ssimg.getGraphics() ;
        g.drawImage(img, 0, 0, Color.white, null) ;

        //保存ファイル名の作成
        String fname = jikoku ;

        //ファイルに保存
        saveJpg( ssimg , fname );
    }

    /**
     * usbカメラの起動
     */
    public void startCamera()
    {
         //USBカメラとの接続
         try{
        frame = new JFrame("USB-Camera");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        player = Manager.createRealizedPlayer(new MediaLocator("vfw://0"));
        frame.setBounds(50, 50, 640, 480);
        frame.getContentPane().add(player.getVisualComponent());
        frame.setVisible(true);
        player.start();
         }catch(Exception e){};
    }     
    
    //JPG形式で保存
    public void saveJpg(java.awt.image.BufferedImage ssimg ,String fname )
    {
        try {
             java.io.File f = new java.io.File( fname + ".jpg" );
             javax.imageio.ImageIO.write( ssimg , "jpg", f );
             f=null;
            }catch (Exception e) {  e.printStackTrace(); }
    }     
    
}


JAVAで画像を拡大縮小する処理

画像を縮小します。
この作業は、ともさんライブラリから、GazouConvというクラスを用います。
詳しくはこちら

ソースの最初に下記1文を追記
import tomojavalib.gazou.GazouConv;

メソッド takePic( String jikoku )の後ろの方に下記1文を追加すると、 8×6ピクセルのちっちゃな画像が出来上がります。
//画像を縮小する
GazouConv gv = new GazouConv();
gv.setImg( ssimg );
gv.scaleXY(8, 6);
gv.saveJpg("test_8_6.jpg");


この画像をデータベースに登録しますが、そのままでは扱えないので、色情報を文字に変換することにします。
6×8ピクセルの画像はしたの図のように、48個の点から出来ています。
1つの点は赤、緑、青それぞれの明るさが0〜254までの数字で表されます。0〜254を16進法で表すと
00〜FFとなるので、1つのピクセルの情報を6文字FFFFFFで置き換えることが出来ます。
48ピクセルであれば288文字で示すことが出来ます。
ここでは画像情報を288文字の文字列に変換し、その後データベースへ格納することにします。
画像ピクセル


この作業はともさんライブラリGazouConv下記メソッドを2つ追加して出来るようにしました。
bimgToString()は画像情報を文字に、 StringToBimg()は文字列を画像情報に、それぞれ変換します。

元変換元画像 ←この画像は

↓こんな文字列になります。
00080006004b6500404b2ffff523fded22d8e348e0ee62dfe300534f38d8e843f6fa14efdb0ef0dc41ffff00515a58d8d900453f35f6f324f2e508f1d108f6d624fff424dcda50d7d1005a53003e3d3ae0d63ff3da4affee1ad8ce45e5e5016567003b3e00354881bbc7003539003f426ed9e37ad3e5283c54645670040b27282c455857694e61720040541447622f1b3e4b133a


    /**
     *画像の内容を読み込んで文字列に変換します
     * @param x 画像の幅
     * @param y 画像の高さ
     * @param bimg 画像のイメージ
     * @return 文字列化した画像情報 最初の4文字:幅、次4文字:高さ、以降画像情報(1ピクセル6文字)xxxxyyyyffffff
     */
    public String bimgToString( int x, int y, java.awt.image.BufferedImage bimg )
    {
    String s = "";
    String stmp = "";
    stmp = Integer.toHexString(x);
    while( stmp.length() < 4 )     {stmp = "0"+stmp;}
    s= s+stmp;
    stmp = Integer.toHexString(y);
    while( stmp.length() < 4 )     {stmp = "0"+stmp;}
    s= s+stmp;
    for(int iy=0 ; iy < y ;iy++)
     {
          for(int ix=0 ; ix < x ;ix++)
          {
                   stmp = Integer.toHexString( bimg.getRGB(ix, iy) );
                   stmp= stmp.substring(2);
                   s= s+stmp;
          }
     }
    return s;
    }
    
    /**
     *文字列を読み込んでバッファードイメージにに変換します
     * @param  simg  文字化した画像情報
     * @return bimg 画像のイメージ
     */
    public java.awt.image.BufferedImage StringToBimg( String simg )
    {
    int x = Integer.parseInt( simg.substring(0, 4) , 16 );
    int y = Integer.parseInt( simg.substring(4, 8) , 16 );               
    java.awt.image.BufferedImage bimg = new java.awt.image.BufferedImage( x , y , java.awt.image.BufferedImage.TYPE_INT_RGB );     
    int si = 8;
    for(int iy=0 ; iy < y ;iy++)
     {
          for(int ix=0 ; ix < x ;ix++)
          {
               bimg.setRGB(ix, iy, Integer.parseInt( (simg.substring(si,si+6)) , 16 ) );
               si = si + 6;
          }
     }

    return bimg;
    }     


JAVAでデータベースにアクセスするための準備

さて、今度はデータベースの準備をします。
使うのはAccess。普通のデータベースソフトです。
テーブルを作成して、テキスト型のmmsec、メモ型のiro、メモ型のholderというフィールドを作りました。
mmsecには2010/1/1 00:00:00から撮影時刻までの経過ミリ秒、iroには先ほど作った文字列を入れます。 holderには撮影画像を保存したフォルダ名とファイル名を入れます。
ACCESSテーブル

データベースが出来たら、JAVAから接続できるようにWindows上で設定します。やり方は検索してみてください。



データベースに書き込む部分を書きます。
ソースの最初に下記1文を追記
import tomojavalib.comm.DbsComm;

変数の定義のところに下記1文を追記
DbsComm dbc ; //データベース

IntTakePic()に下記追記
 //データベースの準備
  String dbs = "teiten86";
  String member[] = { "mmsec" , "iro" , "holder" };
  dbc = new DbsComm( dbs , member );


mmsecの計算は下記のようにします。
//2010/1/1 00:00:00からの経過mmsecを計算
long mmsec = c.getTimeInMillis();
c.clear();
c.set(2010, 1, 1, 0, 0, 0);
mmsec = mmsec - c.getTimeInMillis();
  dbc = new DbsComm( dbs , member );


holderは下記の要領で作成。
cドライブに年月日のホルダをあらかじめ作っておき、そこへ撮影時刻のファイル名の画像を入れます。
String holder;
String stmp;
int yr = c.get(Calendar.YEAR); int mn = c.get(Calendar.MONTH);
int dy = c.get(Calendar.DATE);
holder = "c:\\" + Integer.toString(yr);
stmp = Integer.toString( mn+1 ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
stmp = Integer.toString( dy ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
holder = holder + "\\" + jikoku +".jpg";


データベースへ格納するデータを揃えたら、登録します。
//データベースへ登録
try{
String addata[] = {mmsec+"" , gv.bimgToString(8, 6, ssimg) , holder };
dbc.addData( addata );
}catch (Exception e){ e.printStackTrace(); }

tekePic()の中身はこんな感じになります。
    public void takePic( Calendar c )
    {
         //現在時刻の文字列を作成
         tomojavalib.util.Jikoku j = new tomojavalib.util.Jikoku();
         String jikoku = j.calendarToString1(c);     
         System.out.println( "現在の時刻 " + jikoku + flug1 + flug2);
         //ホルダ情報を作成
          String holder;
          String stmp;
          int yr = c.get(Calendar.YEAR); int mn = c.get(Calendar.MONTH);
          int dy = c.get(Calendar.DATE);
          holder = "c:\\" + Integer.toString(yr);
          stmp = Integer.toString( mn+1 ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
          stmp = Integer.toString( dy   ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
          holder = holder + "\\" + jikoku +".jpg";
         System.out.println( holder );
         //2010/1/1 00:00:00からの経過mmsecを計算
         long mmsec = c.getTimeInMillis();
         c.clear();
         c.set(2010, 1, 1, 0, 0, 0);
         mmsec = mmsec - c.getTimeInMillis();
         System.out.println( mmsec );
         //画像をバファードイメージに入れる
        FrameGrabbingControl frameGrabber  = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
        Buffer buf = frameGrabber.grabFrame();
        BufferToImage b2i = new BufferToImage((VideoFormat) buf.getFormat());
        img = b2i.createImage(buf);
        ssimg = new java.awt.image.BufferedImage( 640, 480 ,java.awt.image.BufferedImage.TYPE_INT_RGB  );
         Graphics g = null;
        g = ssimg.getGraphics() ;
        g.drawImage(img, 0, 0, Color.white, null) ;
        

        
        //画像保存/縮小の準備
         GazouConv gv = new GazouConv();
         gv.setImg( ssimg );     
        //画像を保存する
        gv.saveJpg( holder );
         //画像を縮小する
        gv.scaleXY(8, 6);
         
         System.out.println(mmsec + gv.bimgToString(8, 6, ssimg) + holder );
         
         //データベースへ登録
         try{
               String addata[] = {mmsec+"" , gv.bimgToString(8, 6, ssimg) , holder };
                dbc.addData( addata );
               }catch (Exception e){   e.printStackTrace(); }          
    
    }


さて、これでプログラム完成!
下記条件で動きます。
Windows上。
USBカメラを接続
Java,JMFのインストール
Access、およびデータベースのWindowsへの登録
Cドライブ直下に年、月、日のフォルダを作成


これは画像を撮影してデータベースに入れるプログラムなので、 これとは別にデータベースからデータを読み込んでモザイク画像に仕上げるプログラムが 必要になります。こちらはまた後の機会に作成しましょう。


完成プログラムは下記

JAVAでUSBカメラ制御、定点観測するためのプログラムソース


package tomojavalib.usbcamera;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Calendar;

import javax.media.Buffer;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.JFrame;

import tomojavalib.comm.DbsComm;
import tomojavalib.gazou.GazouConv;


public class IntTakePic implements Runnable
{
    //変数の定義
    Thread timer;
    boolean flug1 = false; //前回調査した分が0,10,20,30,40,50であるか
    boolean flug2 = false; //今回調査した分が0,10,20,30,40,50であるか
    Image img = null;
    java.awt.image.BufferedImage ssimg = null;
    JFrame frame =null;
    Player player = null;
    DbsComm dbc  ; //データベース
    
    public static void main(String args[]) throws Exception 
    {
         IntTakePic i = new IntTakePic();
    }
    
    public IntTakePic()
    {
         //データベースの準備
          String dbs = "teiten86";
          String member[] = { "mmsec" , "iro" , "holder" };
          dbc = new DbsComm( dbs , member );
         //usbカメラを動かす
          startCamera();
          //タイマースタート
          timer = new Thread(this);
          timer.start();
    }
    
    public void run()
    {
         //無限ループ
          do{
           //10秒休憩
           try{ timer.sleep(5000);}catch(InterruptedException e){}
           check();
          }while(true);
    }

    /**
     * 現在の時刻を調べ、0,10,20,30,40,50分になったばかりであればtake()の処理を実行
     */
    public void check()
    {
         Calendar c = Calendar.getInstance();     //一時使用カレンダの作成
         int min = c.get(Calendar.MINUTE);
         flug2 = false;
         if(min==0){flug2 = true;} else if(min==10){flug2 = true;} else if(min==20){flug2 = true;} else if(min==30){flug2 = true;}
         else if(min==40){flug2 = true;} else if(min==50){flug2 = true;}
         if( flug1 == false ){ if( flug2 ==true ){ takePic( c ); } }
         //takePic( c ); //デバッグ用
         flug1 = false;
         if(min==0){flug1 = true;} else if(min==10){flug1 = true;} else if(min==20){flug1 = true;} else if(min==30){flug1 = true;}
         else if(min==40){flug1 = true;} else if(min==50){flug1 = true;}          
    }
    
    
    /**
     * 画像の撮影
     * @param c :現在時刻
     */
    public void takePic( Calendar c )
    {
         //現在時刻の文字列を作成
         tomojavalib.util.Jikoku j = new tomojavalib.util.Jikoku();
         String jikoku = j.calendarToString1(c);     
         System.out.println( "現在の時刻 " + jikoku + flug1 + flug2);
         //ホルダ情報を作成
          String holder;
          String stmp;
          int yr = c.get(Calendar.YEAR); int mn = c.get(Calendar.MONTH);
          int dy = c.get(Calendar.DATE);
          holder = "c:\\cam\\" + Integer.toString(yr);
          stmp = Integer.toString( mn+1 ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
          stmp = Integer.toString( dy   ); if( stmp.length() < 2){ stmp = "0" + stmp; } holder = holder + "\\" + stmp;
          holder = holder + "\\" + jikoku +".jpg";
         System.out.println( holder );
         //2010/1/1 00:00:00からの経過mmsecを計算
         long mmsec = c.getTimeInMillis();
         c.clear();
         c.set(2010, 1, 1, 0, 0, 0);
         mmsec = mmsec - c.getTimeInMillis();
         System.out.println( mmsec );
         //画像をバファードイメージに入れる
        FrameGrabbingControl frameGrabber  = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
        Buffer buf = frameGrabber.grabFrame();
        BufferToImage b2i = new BufferToImage((VideoFormat) buf.getFormat());
        img = b2i.createImage(buf);
        ssimg = new java.awt.image.BufferedImage( 640, 480 ,java.awt.image.BufferedImage.TYPE_INT_RGB  );
         Graphics g = null;
        g = ssimg.getGraphics() ;
        g.drawImage(img, 0, 0, Color.white, null) ;
        

        
        //画像保存/縮小の準備
         GazouConv gv = new GazouConv();
         gv.setImg( ssimg );     
        //画像を保存する
        gv.saveJpg( holder );
         //画像を縮小する
        gv.scaleXY(8, 6);
         
         System.out.println(mmsec + gv.bimgToString(8, 6, ssimg) + holder );
         
         //データベースへ登録
         try{
               String addata[] = {mmsec+"" , gv.bimgToString(8, 6, ssimg) , holder };
                dbc.addData( addata );
               }catch (Exception e){   e.printStackTrace(); }          
    
    }

広告

    /**
     * usbカメラの起動
     */
    public void startCamera()
    {
         //USBカメラとの接続
         try{
        frame = new JFrame("USB-Camera");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        player = Manager.createRealizedPlayer(new MediaLocator("vfw://0"));
        frame.setBounds(50, 50, 640, 480);
        frame.getContentPane().add(player.getVisualComponent());
        frame.setVisible(true);
        player.start();
         }catch(Exception e){};
    }     
    

    
}

最終更新日: 2012-05-23 06:01:07

ともさんのHP >プロブラミング >USBカメラをJAVAで制御して定点観測 >定点観測カメラソフトの作成

このエントリーをはてなブックマークに追加
広告
おすすめ記事
新着ページ

和風コートの作り方  
ホオノキ  
雑草でグリーンカーテン  
エケベリア植え替え  
E型肝炎体験記  
フラワースタンドの自作  
ウエスト切り替えワンピースの作りかた  
メーラーの引っ越し  
RaspberryPi用Javaサンプルプログラム  
須屋  
3Dシーンに2Dコントロールを表示  

私の他のサイト

ともさんの箱庭(ブログ)
家庭菜園
3D-CAD
洋裁CAD

いいねなど

 RSS 
PageSpeedInsights
html5チェック

Author: Tomoyuki Ito

このサイトの文章・写真の無断転載を禁じます